docs: bump version to 5.0b2 and regenerate documentation
This commit is contained in:
+51
-36
@@ -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>
|
||||
@@ -551,6 +551,13 @@ class Preload:
|
||||
</code></pre>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-submodules">Sub-modules</h2>
|
||||
<dl>
|
||||
<dt><code class="name"><a title="connpy.tests" href="tests/index.html">connpy.tests</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
@@ -623,8 +630,8 @@ class Preload:
|
||||
if not (isinstance(node.test, ast.Compare) and
|
||||
isinstance(node.test.left, ast.Name) and
|
||||
node.test.left.id == '__name__' and
|
||||
isinstance(node.test.comparators[0], ast.Str) and
|
||||
node.test.comparators[0].s == '__main__'):
|
||||
((hasattr(ast, 'Str') and isinstance(node.test.comparators[0], getattr(ast, 'Str')) and node.test.comparators[0].s == '__main__') or
|
||||
(hasattr(ast, 'Constant') and isinstance(node.test.comparators[0], getattr(ast, 'Constant')) and node.test.comparators[0].value == '__main__'))):
|
||||
return "Only __name__ == __main__ If is allowed"
|
||||
|
||||
elif not isinstance(node, (ast.FunctionDef, ast.ClassDef, ast.Import, ast.ImportFrom, ast.Pass)):
|
||||
@@ -758,8 +765,8 @@ class Preload:
|
||||
if not (isinstance(node.test, ast.Compare) and
|
||||
isinstance(node.test.left, ast.Name) and
|
||||
node.test.left.id == '__name__' and
|
||||
isinstance(node.test.comparators[0], ast.Str) and
|
||||
node.test.comparators[0].s == '__main__'):
|
||||
((hasattr(ast, 'Str') and isinstance(node.test.comparators[0], getattr(ast, 'Str')) and node.test.comparators[0].s == '__main__') or
|
||||
(hasattr(ast, 'Constant') and isinstance(node.test.comparators[0], getattr(ast, 'Constant')) and node.test.comparators[0].value == '__main__'))):
|
||||
return "Only __name__ == __main__ If is allowed"
|
||||
|
||||
elif not isinstance(node, (ast.FunctionDef, ast.ClassDef, ast.Import, ast.ImportFrom, ast.Pass)):
|
||||
@@ -1217,7 +1224,7 @@ class ai:
|
||||
if isinstance(commands, str):
|
||||
try:
|
||||
commands = json.loads(commands)
|
||||
except:
|
||||
except ValueError:
|
||||
commands = [c.strip() for c in commands.split('\n') if c.strip()]
|
||||
|
||||
# Expand multi-line commands within a list (in case the AI packs them)
|
||||
@@ -1616,9 +1623,10 @@ class ai:
|
||||
response = completion(model=model, messages=safe_messages, tools=[], api_key=key)
|
||||
resp_msg = response.choices[0].message
|
||||
messages.append(resp_msg.model_dump(exclude_none=True))
|
||||
except:
|
||||
pass
|
||||
|
||||
except Exception as e:
|
||||
if status:
|
||||
status.update(f"[bold red]Error fetching summary: {e}[/bold red]")
|
||||
printer.warning(f"Failed to fetch final summary from LLM: {e}")
|
||||
except KeyboardInterrupt:
|
||||
if status: status.update("[bold red]Interrupted! Closing pending tasks...")
|
||||
last_msg = messages[-1]
|
||||
@@ -1631,7 +1639,7 @@ class ai:
|
||||
response = completion(model=model, messages=safe_messages, tools=tools, api_key=key)
|
||||
resp_msg = response.choices[0].message
|
||||
messages.append(resp_msg.model_dump(exclude_none=True))
|
||||
except: pass
|
||||
except Exception: pass
|
||||
finally:
|
||||
try:
|
||||
log_dir = self.config.defaultdir
|
||||
@@ -1641,7 +1649,7 @@ class ai:
|
||||
if os.path.exists(log_path):
|
||||
try:
|
||||
with open(log_path, "r") as f: hist = json.load(f)
|
||||
except: hist = []
|
||||
except (IOError, json.JSONDecodeError): hist = []
|
||||
hist.append({"timestamp": datetime.datetime.now().isoformat(), "roles": {"strategic_engine": self.architect_model, "execution_engine": self.engineer_model}, "session": messages})
|
||||
with open(log_path, "w") as f: json.dump(hist[-10:], f, indent=4)
|
||||
except Exception as e:
|
||||
@@ -1664,7 +1672,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>
|
||||
@@ -1925,9 +1933,10 @@ def ask(self, user_input, dryrun=False, chat_history=None, status=None, debug=Fa
|
||||
response = completion(model=model, messages=safe_messages, tools=[], api_key=key)
|
||||
resp_msg = response.choices[0].message
|
||||
messages.append(resp_msg.model_dump(exclude_none=True))
|
||||
except:
|
||||
pass
|
||||
|
||||
except Exception as e:
|
||||
if status:
|
||||
status.update(f"[bold red]Error fetching summary: {e}[/bold red]")
|
||||
printer.warning(f"Failed to fetch final summary from LLM: {e}")
|
||||
except KeyboardInterrupt:
|
||||
if status: status.update("[bold red]Interrupted! Closing pending tasks...")
|
||||
last_msg = messages[-1]
|
||||
@@ -1940,7 +1949,7 @@ def ask(self, user_input, dryrun=False, chat_history=None, status=None, debug=Fa
|
||||
response = completion(model=model, messages=safe_messages, tools=tools, api_key=key)
|
||||
resp_msg = response.choices[0].message
|
||||
messages.append(resp_msg.model_dump(exclude_none=True))
|
||||
except: pass
|
||||
except Exception: pass
|
||||
finally:
|
||||
try:
|
||||
log_dir = self.config.defaultdir
|
||||
@@ -1950,7 +1959,7 @@ def ask(self, user_input, dryrun=False, chat_history=None, status=None, debug=Fa
|
||||
if os.path.exists(log_path):
|
||||
try:
|
||||
with open(log_path, "r") as f: hist = json.load(f)
|
||||
except: hist = []
|
||||
except (IOError, json.JSONDecodeError): hist = []
|
||||
hist.append({"timestamp": datetime.datetime.now().isoformat(), "roles": {"strategic_engine": self.architect_model, "execution_engine": self.engineer_model}, "session": messages})
|
||||
with open(log_path, "w") as f: json.dump(hist[-10:], f, indent=4)
|
||||
except Exception as e:
|
||||
@@ -2123,7 +2132,7 @@ def confirm(self, user_input): return True</code></pre>
|
||||
if isinstance(commands, str):
|
||||
try:
|
||||
commands = json.loads(commands)
|
||||
except:
|
||||
except ValueError:
|
||||
commands = [c.strip() for c in commands.split('\n') if c.strip()]
|
||||
|
||||
# Expand multi-line commands within a list (in case the AI packs them)
|
||||
@@ -2246,7 +2255,7 @@ class configfile:
|
||||
try:
|
||||
with open(pathfile, "r") as f:
|
||||
configdir = f.read().strip()
|
||||
except:
|
||||
except (FileNotFoundError, IOError):
|
||||
with open(pathfile, "w") as f:
|
||||
f.write(str(defaultdir))
|
||||
configdir = defaultdir
|
||||
@@ -2306,7 +2315,8 @@ class configfile:
|
||||
with open(conf, "w") as f:
|
||||
json.dump(newconfig, f, indent = 4)
|
||||
f.close()
|
||||
except:
|
||||
except (IOError, OSError) as e:
|
||||
printer.error(f"Failed to save config: {e}")
|
||||
return 1
|
||||
return 0
|
||||
|
||||
@@ -2391,12 +2401,12 @@ class configfile:
|
||||
if profile:
|
||||
try:
|
||||
newfolder[node_name][key] = self.profiles[profile.group(1)][key]
|
||||
except:
|
||||
except KeyError:
|
||||
newfolder[node_name][key] = ""
|
||||
elif value == '' and key == "protocol":
|
||||
try:
|
||||
newfolder[node_name][key] = self.profiles["default"][key]
|
||||
except:
|
||||
except KeyError:
|
||||
newfolder[node_name][key] = "ssh"
|
||||
|
||||
newfolder = {"{}{}".format(k,unique):v for k,v in newfolder.items()}
|
||||
@@ -2417,12 +2427,12 @@ class configfile:
|
||||
if profile:
|
||||
try:
|
||||
newnode[key] = self.profiles[profile.group(1)][key]
|
||||
except:
|
||||
except KeyError:
|
||||
newnode[key] = ""
|
||||
elif value == '' and key == "protocol":
|
||||
try:
|
||||
newnode[key] = self.profiles["default"][key]
|
||||
except:
|
||||
except KeyError:
|
||||
newnode[key] = "ssh"
|
||||
return newnode
|
||||
|
||||
@@ -2577,12 +2587,12 @@ class configfile:
|
||||
if profile:
|
||||
try:
|
||||
nodes[node][key] = self.profiles[profile.group(1)][key]
|
||||
except:
|
||||
except KeyError:
|
||||
nodes[node][key] = ""
|
||||
elif value == '' and key == "protocol":
|
||||
try:
|
||||
nodes[node][key] = self.profiles["default"][key]
|
||||
except:
|
||||
except KeyError:
|
||||
nodes[node][key] = "ssh"
|
||||
return nodes
|
||||
|
||||
@@ -2780,12 +2790,12 @@ def getitem(self, unique, keys = None, extract = False):
|
||||
if profile:
|
||||
try:
|
||||
newfolder[node_name][key] = self.profiles[profile.group(1)][key]
|
||||
except:
|
||||
except KeyError:
|
||||
newfolder[node_name][key] = ""
|
||||
elif value == '' and key == "protocol":
|
||||
try:
|
||||
newfolder[node_name][key] = self.profiles["default"][key]
|
||||
except:
|
||||
except KeyError:
|
||||
newfolder[node_name][key] = "ssh"
|
||||
|
||||
newfolder = {"{}{}".format(k,unique):v for k,v in newfolder.items()}
|
||||
@@ -2806,12 +2816,12 @@ def getitem(self, unique, keys = None, extract = False):
|
||||
if profile:
|
||||
try:
|
||||
newnode[key] = self.profiles[profile.group(1)][key]
|
||||
except:
|
||||
except KeyError:
|
||||
newnode[key] = ""
|
||||
elif value == '' and key == "protocol":
|
||||
try:
|
||||
newnode[key] = self.profiles["default"][key]
|
||||
except:
|
||||
except KeyError:
|
||||
newnode[key] = "ssh"
|
||||
return newnode</code></pre>
|
||||
</details>
|
||||
@@ -2979,12 +2989,12 @@ class node:
|
||||
if profile and config != '':
|
||||
try:
|
||||
setattr(self,key,config.profiles[profile.group(1)][key])
|
||||
except:
|
||||
except KeyError:
|
||||
setattr(self,key,"")
|
||||
elif attr[key] == '' and key == "protocol":
|
||||
try:
|
||||
setattr(self,key,config.profiles["default"][key])
|
||||
except:
|
||||
except (KeyError, AttributeError):
|
||||
setattr(self,key,"ssh")
|
||||
else:
|
||||
setattr(self,key,attr[key])
|
||||
@@ -3003,12 +3013,12 @@ class node:
|
||||
if profile:
|
||||
try:
|
||||
self.jumphost[key] = config.profiles[profile.group(1)][key]
|
||||
except:
|
||||
except KeyError:
|
||||
self.jumphost[key] = ""
|
||||
elif self.jumphost[key] == '' and key == "protocol":
|
||||
try:
|
||||
self.jumphost[key] = config.profiles["default"][key]
|
||||
except:
|
||||
except KeyError:
|
||||
self.jumphost[key] = "ssh"
|
||||
if isinstance(self.jumphost["password"],list):
|
||||
jumphost_password = []
|
||||
@@ -3053,7 +3063,7 @@ class node:
|
||||
try:
|
||||
decrypted = decryptor.decrypt(ast.literal_eval(passwd)).decode("utf-8")
|
||||
dpass.append(decrypted)
|
||||
except:
|
||||
except Exception:
|
||||
raise ValueError("Missing or corrupted key")
|
||||
return dpass
|
||||
|
||||
@@ -4579,6 +4589,11 @@ def test(self, commands, expected, vars = None,*, prompt = None, parallel = 10,
|
||||
</ul>
|
||||
</div>
|
||||
<ul id="index">
|
||||
<li><h3><a href="#header-submodules">Sub-modules</a></h3>
|
||||
<ul>
|
||||
<li><code><a title="connpy.tests" href="tests/index.html">connpy.tests</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-classes">Classes</a></h3>
|
||||
<ul>
|
||||
<li>
|
||||
@@ -4631,7 +4646,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>
|
||||
|
||||
@@ -0,0 +1,264 @@
|
||||
<!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.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>
|
||||
<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.conftest</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<p>Shared fixtures for connpy tests.</p>
|
||||
<p>All tests use tmp_path to create isolated config/keys.
|
||||
No test touches ~/.config/conn/</p>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-functions">Functions</h2>
|
||||
<dl>
|
||||
<dt id="connpy.tests.conftest.ai_config"><code class="name flex">
|
||||
<span>def <span class="ident">ai_config</span></span>(<span>tmp_config_dir)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.fixture
|
||||
def ai_config(tmp_config_dir):
|
||||
"""Create a configfile with AI keys configured for AI tests."""
|
||||
config_file = tmp_config_dir / "config.json"
|
||||
data = {
|
||||
"config": {
|
||||
"case": False, "idletime": 30, "fzf": False,
|
||||
"ai": {
|
||||
"engineer_model": "test/test-model",
|
||||
"engineer_api_key": "test-engineer-key",
|
||||
"architect_model": "test/test-architect",
|
||||
"architect_api_key": "test-architect-key"
|
||||
}
|
||||
},
|
||||
"connections": SAMPLE_CONNECTIONS,
|
||||
"profiles": SAMPLE_PROFILES
|
||||
}
|
||||
config_file.write_text(json.dumps(data, indent=4))
|
||||
from connpy.configfile import configfile
|
||||
return configfile(conf=str(config_file), key=str(tmp_config_dir / ".osk"))</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Create a configfile with AI keys configured for AI tests.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.conftest.config"><code class="name flex">
|
||||
<span>def <span class="ident">config</span></span>(<span>tmp_config_dir)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.fixture
|
||||
def config(tmp_config_dir):
|
||||
"""Create a configfile instance pointing to tmp directory."""
|
||||
from connpy.configfile import configfile
|
||||
conf_path = str(tmp_config_dir / "config.json")
|
||||
key_path = str(tmp_config_dir / ".osk")
|
||||
return configfile(conf=conf_path, key=key_path)</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Create a configfile instance pointing to tmp directory.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.conftest.mock_litellm"><code class="name flex">
|
||||
<span>def <span class="ident">mock_litellm</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.fixture
|
||||
def mock_litellm():
|
||||
"""Mock litellm.completion for AI tests."""
|
||||
with patch("connpy.ai.completion") as mock_comp:
|
||||
# Create a default response
|
||||
msg = MagicMock()
|
||||
msg.content = "Test response from AI"
|
||||
msg.tool_calls = None
|
||||
msg.role = "assistant"
|
||||
msg.model_dump.return_value = {
|
||||
"role": "assistant",
|
||||
"content": "Test response from AI"
|
||||
}
|
||||
|
||||
choice = MagicMock()
|
||||
choice.message = msg
|
||||
|
||||
response = MagicMock()
|
||||
response.choices = [choice]
|
||||
response.usage = MagicMock()
|
||||
response.usage.prompt_tokens = 100
|
||||
response.usage.completion_tokens = 50
|
||||
response.usage.total_tokens = 150
|
||||
|
||||
mock_comp.return_value = response
|
||||
|
||||
yield {
|
||||
"completion": mock_comp,
|
||||
"response": response,
|
||||
"message": msg,
|
||||
"choice": choice
|
||||
}</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Mock litellm.completion for AI tests.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.conftest.mock_pexpect"><code class="name flex">
|
||||
<span>def <span class="ident">mock_pexpect</span></span>(<span>)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.fixture
|
||||
def mock_pexpect():
|
||||
"""Mock pexpect.spawn for connection tests."""
|
||||
with patch("connpy.core.pexpect") as mock_pexp:
|
||||
child = MagicMock()
|
||||
child.before = b""
|
||||
child.after = b"router#"
|
||||
child.readline.return_value = b""
|
||||
child.child_fd = 3
|
||||
mock_pexp.spawn.return_value = child
|
||||
mock_pexp.EOF = object()
|
||||
mock_pexp.TIMEOUT = object()
|
||||
|
||||
# Also mock fdpexpect
|
||||
with patch("connpy.core.fdpexpect", create=True) as mock_fd:
|
||||
mock_fd.fdspawn.return_value = MagicMock()
|
||||
yield {
|
||||
"pexpect": mock_pexp,
|
||||
"child": child,
|
||||
"fdpexpect": mock_fd
|
||||
}</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Mock pexpect.spawn for connection tests.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.conftest.populated_config"><code class="name flex">
|
||||
<span>def <span class="ident">populated_config</span></span>(<span>tmp_config_dir)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.fixture
|
||||
def populated_config(tmp_config_dir):
|
||||
"""Create a configfile with sample nodes/profiles pre-loaded."""
|
||||
config_file = tmp_config_dir / "config.json"
|
||||
data = {
|
||||
"config": {"case": False, "idletime": 30, "fzf": False},
|
||||
"connections": SAMPLE_CONNECTIONS,
|
||||
"profiles": SAMPLE_PROFILES
|
||||
}
|
||||
config_file.write_text(json.dumps(data, indent=4))
|
||||
from connpy.configfile import configfile
|
||||
return configfile(conf=str(config_file), key=str(tmp_config_dir / ".osk"))</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Create a configfile with sample nodes/profiles pre-loaded.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.conftest.tmp_config_dir"><code class="name flex">
|
||||
<span>def <span class="ident">tmp_config_dir</span></span>(<span>tmp_path)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.fixture
|
||||
def tmp_config_dir(tmp_path):
|
||||
"""Create an isolated config directory with config.json and RSA key."""
|
||||
config_dir = tmp_path / ".config" / "conn"
|
||||
config_dir.mkdir(parents=True)
|
||||
plugins_dir = config_dir / "plugins"
|
||||
plugins_dir.mkdir()
|
||||
|
||||
# Write config.json
|
||||
config_file = config_dir / "config.json"
|
||||
config_file.write_text(json.dumps(DEFAULT_CONFIG, indent=4))
|
||||
os.chmod(str(config_file), 0o600)
|
||||
|
||||
# Write .folder (points to itself)
|
||||
folder_file = config_dir / ".folder"
|
||||
folder_file.write_text(str(config_dir))
|
||||
|
||||
# Generate RSA key
|
||||
key = RSA.generate(2048)
|
||||
key_file = config_dir / ".osk"
|
||||
key_file.write_bytes(key.export_key("PEM"))
|
||||
os.chmod(str(key_file), 0o600)
|
||||
|
||||
return config_dir</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Create an isolated config directory with config.json and RSA key.</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="two-column">
|
||||
<li><code><a title="connpy.tests.conftest.ai_config" href="#connpy.tests.conftest.ai_config">ai_config</a></code></li>
|
||||
<li><code><a title="connpy.tests.conftest.config" href="#connpy.tests.conftest.config">config</a></code></li>
|
||||
<li><code><a title="connpy.tests.conftest.mock_litellm" href="#connpy.tests.conftest.mock_litellm">mock_litellm</a></code></li>
|
||||
<li><code><a title="connpy.tests.conftest.mock_pexpect" href="#connpy.tests.conftest.mock_pexpect">mock_pexpect</a></code></li>
|
||||
<li><code><a title="connpy.tests.conftest.populated_config" href="#connpy.tests.conftest.populated_config">populated_config</a></code></li>
|
||||
<li><code><a title="connpy.tests.conftest.tmp_config_dir" href="#connpy.tests.conftest.tmp_config_dir">tmp_config_dir</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,118 @@
|
||||
<!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 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</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.tests.conftest" href="conftest.html">connpy.tests.conftest</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Shared fixtures for connpy tests …</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="connpy.tests.test_ai" href="test_ai.html">connpy.tests.test_ai</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Tests for connpy.ai module.</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="connpy.tests.test_api" href="test_api.html">connpy.tests.test_api</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Tests for connpy.api module — Flask routes.</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="connpy.tests.test_completion" href="test_completion.html">connpy.tests.test_completion</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Tests for connpy.completion module.</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="connpy.tests.test_configfile" href="test_configfile.html">connpy.tests.test_configfile</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Tests for connpy.configfile module.</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="connpy.tests.test_core" href="test_core.html">connpy.tests.test_core</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Tests for connpy.core module — node and nodes classes.</p></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>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="connpy.tests.test_plugins" href="test_plugins.html">connpy.tests.test_plugins</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Tests for connpy.plugins module.</p></div>
|
||||
</dd>
|
||||
<dt><code class="name"><a title="connpy.tests.test_printer" href="test_printer.html">connpy.tests.test_printer</a></code></dt>
|
||||
<dd>
|
||||
<div class="desc"><p>Tests for connpy.printer module.</p></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.tests.conftest" href="conftest.html">connpy.tests.conftest</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_ai" href="test_ai.html">connpy.tests.test_ai</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_api" href="test_api.html">connpy.tests.test_api</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_completion" href="test_completion.html">connpy.tests.test_completion</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_configfile" href="test_configfile.html">connpy.tests.test_configfile</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_hooks" href="test_hooks.html">connpy.tests.test_hooks</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>
|
||||
</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,882 @@
|
||||
<!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_api API documentation</title>
|
||||
<meta name="description" content="Tests for connpy.api module — Flask routes.">
|
||||
<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_api</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<p>Tests for connpy.api module — Flask routes.</p>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-functions">Functions</h2>
|
||||
<dl>
|
||||
<dt id="connpy.tests.test_api.api_client"><code class="name flex">
|
||||
<span>def <span class="ident">api_client</span></span>(<span>populated_config)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@pytest.fixture
|
||||
def api_client(populated_config):
|
||||
"""Create a Flask test client with a populated config."""
|
||||
from connpy.api import app
|
||||
app.custom_config = populated_config
|
||||
app.config["TESTING"] = True
|
||||
with app.test_client() as client:
|
||||
yield client</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Create a Flask test client with a populated config.</p></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-classes">Classes</h2>
|
||||
<dl>
|
||||
<dt id="connpy.tests.test_api.TestAskAI"><code class="flex name class">
|
||||
<span>class <span class="ident">TestAskAI</span></span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class TestAskAI:
|
||||
@patch("connpy.api.myai")
|
||||
def test_ask_ai(self, mock_ai_cls, api_client):
|
||||
mock_instance = MagicMock()
|
||||
mock_instance.ask.return_value = {"response": "AI says hello"}
|
||||
mock_ai_cls.return_value = mock_instance
|
||||
|
||||
response = api_client.post("/ask_ai", json={
|
||||
"input": "list my routers"
|
||||
})
|
||||
data = response.get_json()
|
||||
assert data is not None
|
||||
|
||||
@patch("connpy.api.myai")
|
||||
def test_ask_ai_with_dryrun(self, mock_ai_cls, api_client):
|
||||
mock_instance = MagicMock()
|
||||
mock_instance.ask.return_value = {"response": "dry run"}
|
||||
mock_ai_cls.return_value = mock_instance
|
||||
|
||||
response = api_client.post("/ask_ai", json={
|
||||
"input": "test",
|
||||
"dryrun": True
|
||||
})
|
||||
assert response.status_code == 200
|
||||
|
||||
@patch("connpy.api.myai")
|
||||
def test_ask_ai_with_history(self, mock_ai_cls, api_client):
|
||||
mock_instance = MagicMock()
|
||||
mock_instance.ask.return_value = {"response": "with history"}
|
||||
mock_ai_cls.return_value = mock_instance
|
||||
|
||||
response = api_client.post("/ask_ai", json={
|
||||
"input": "follow up",
|
||||
"chat_history": [
|
||||
{"role": "user", "content": "previous"},
|
||||
{"role": "assistant", "content": "answer"}
|
||||
]
|
||||
})
|
||||
assert response.status_code == 200</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="connpy.tests.test_api.TestAskAI.test_ask_ai"><code class="name flex">
|
||||
<span>def <span class="ident">test_ask_ai</span></span>(<span>self, mock_ai_cls, api_client)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@patch("connpy.api.myai")
|
||||
def test_ask_ai(self, mock_ai_cls, api_client):
|
||||
mock_instance = MagicMock()
|
||||
mock_instance.ask.return_value = {"response": "AI says hello"}
|
||||
mock_ai_cls.return_value = mock_instance
|
||||
|
||||
response = api_client.post("/ask_ai", json={
|
||||
"input": "list my routers"
|
||||
})
|
||||
data = response.get_json()
|
||||
assert data is not None</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_api.TestAskAI.test_ask_ai_with_dryrun"><code class="name flex">
|
||||
<span>def <span class="ident">test_ask_ai_with_dryrun</span></span>(<span>self, mock_ai_cls, api_client)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@patch("connpy.api.myai")
|
||||
def test_ask_ai_with_dryrun(self, mock_ai_cls, api_client):
|
||||
mock_instance = MagicMock()
|
||||
mock_instance.ask.return_value = {"response": "dry run"}
|
||||
mock_ai_cls.return_value = mock_instance
|
||||
|
||||
response = api_client.post("/ask_ai", json={
|
||||
"input": "test",
|
||||
"dryrun": True
|
||||
})
|
||||
assert response.status_code == 200</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_api.TestAskAI.test_ask_ai_with_history"><code class="name flex">
|
||||
<span>def <span class="ident">test_ask_ai_with_history</span></span>(<span>self, mock_ai_cls, api_client)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@patch("connpy.api.myai")
|
||||
def test_ask_ai_with_history(self, mock_ai_cls, api_client):
|
||||
mock_instance = MagicMock()
|
||||
mock_instance.ask.return_value = {"response": "with history"}
|
||||
mock_ai_cls.return_value = mock_instance
|
||||
|
||||
response = api_client.post("/ask_ai", json={
|
||||
"input": "follow up",
|
||||
"chat_history": [
|
||||
{"role": "user", "content": "previous"},
|
||||
{"role": "assistant", "content": "answer"}
|
||||
]
|
||||
})
|
||||
assert response.status_code == 200</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_api.TestConfirm"><code class="flex name class">
|
||||
<span>class <span class="ident">TestConfirm</span></span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class TestConfirm:
|
||||
@patch("connpy.api.myai")
|
||||
def test_confirm(self, mock_ai_cls, api_client):
|
||||
mock_instance = MagicMock()
|
||||
mock_instance.confirm.return_value = True
|
||||
mock_ai_cls.return_value = mock_instance
|
||||
|
||||
response = api_client.post("/confirm", json={
|
||||
"input": "yes"
|
||||
})
|
||||
assert response.status_code == 200</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="connpy.tests.test_api.TestConfirm.test_confirm"><code class="name flex">
|
||||
<span>def <span class="ident">test_confirm</span></span>(<span>self, mock_ai_cls, api_client)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@patch("connpy.api.myai")
|
||||
def test_confirm(self, mock_ai_cls, api_client):
|
||||
mock_instance = MagicMock()
|
||||
mock_instance.confirm.return_value = True
|
||||
mock_ai_cls.return_value = mock_instance
|
||||
|
||||
response = api_client.post("/confirm", json={
|
||||
"input": "yes"
|
||||
})
|
||||
assert response.status_code == 200</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_api.TestGetNodes"><code class="flex name class">
|
||||
<span>class <span class="ident">TestGetNodes</span></span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class TestGetNodes:
|
||||
def test_get_nodes_no_filter(self, api_client):
|
||||
response = api_client.post("/get_nodes", json={})
|
||||
data = response.get_json()
|
||||
assert response.status_code == 200
|
||||
assert isinstance(data, dict)
|
||||
assert "router1" in data
|
||||
|
||||
def test_get_nodes_with_filter(self, api_client):
|
||||
response = api_client.post("/get_nodes", json={"filter": "router.*"})
|
||||
data = response.get_json()
|
||||
assert "router1" in data
|
||||
assert "host" in data["router1"]
|
||||
|
||||
def test_get_nodes_has_attributes(self, api_client):
|
||||
response = api_client.post("/get_nodes", json={"filter": "router1"})
|
||||
data = response.get_json()
|
||||
if "router1" in data:
|
||||
assert "host" in data["router1"]
|
||||
assert "protocol" in data["router1"]</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="connpy.tests.test_api.TestGetNodes.test_get_nodes_has_attributes"><code class="name flex">
|
||||
<span>def <span class="ident">test_get_nodes_has_attributes</span></span>(<span>self, api_client)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_get_nodes_has_attributes(self, api_client):
|
||||
response = api_client.post("/get_nodes", json={"filter": "router1"})
|
||||
data = response.get_json()
|
||||
if "router1" in data:
|
||||
assert "host" in data["router1"]
|
||||
assert "protocol" in data["router1"]</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_api.TestGetNodes.test_get_nodes_no_filter"><code class="name flex">
|
||||
<span>def <span class="ident">test_get_nodes_no_filter</span></span>(<span>self, api_client)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_get_nodes_no_filter(self, api_client):
|
||||
response = api_client.post("/get_nodes", json={})
|
||||
data = response.get_json()
|
||||
assert response.status_code == 200
|
||||
assert isinstance(data, dict)
|
||||
assert "router1" in data</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_api.TestGetNodes.test_get_nodes_with_filter"><code class="name flex">
|
||||
<span>def <span class="ident">test_get_nodes_with_filter</span></span>(<span>self, api_client)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_get_nodes_with_filter(self, api_client):
|
||||
response = api_client.post("/get_nodes", json={"filter": "router.*"})
|
||||
data = response.get_json()
|
||||
assert "router1" in data
|
||||
assert "host" in data["router1"]</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_api.TestListNodes"><code class="flex name class">
|
||||
<span>class <span class="ident">TestListNodes</span></span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class TestListNodes:
|
||||
def test_list_nodes_no_filter(self, api_client):
|
||||
response = api_client.post("/list_nodes", json={})
|
||||
data = response.get_json()
|
||||
assert response.status_code == 200
|
||||
assert isinstance(data, list)
|
||||
assert "router1" in data
|
||||
|
||||
def test_list_nodes_with_filter(self, api_client):
|
||||
response = api_client.post("/list_nodes", json={"filter": "router.*"})
|
||||
data = response.get_json()
|
||||
assert "router1" in data
|
||||
assert all("router" in n or "Router" in n for n in data)
|
||||
|
||||
def test_list_nodes_case_insensitive(self, api_client):
|
||||
"""Filter is lowercased when case=false."""
|
||||
response = api_client.post("/list_nodes", json={"filter": "ROUTER.*"})
|
||||
data = response.get_json()
|
||||
# Should still match since the filter gets lowercased
|
||||
assert isinstance(data, list)
|
||||
|
||||
def test_list_nodes_no_body(self, api_client):
|
||||
"""No body returns all nodes."""
|
||||
response = api_client.post("/list_nodes",
|
||||
data="",
|
||||
content_type="application/json")
|
||||
data = response.get_json()
|
||||
assert isinstance(data, list)</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="connpy.tests.test_api.TestListNodes.test_list_nodes_case_insensitive"><code class="name flex">
|
||||
<span>def <span class="ident">test_list_nodes_case_insensitive</span></span>(<span>self, api_client)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_list_nodes_case_insensitive(self, api_client):
|
||||
"""Filter is lowercased when case=false."""
|
||||
response = api_client.post("/list_nodes", json={"filter": "ROUTER.*"})
|
||||
data = response.get_json()
|
||||
# Should still match since the filter gets lowercased
|
||||
assert isinstance(data, list)</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Filter is lowercased when case=false.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_api.TestListNodes.test_list_nodes_no_body"><code class="name flex">
|
||||
<span>def <span class="ident">test_list_nodes_no_body</span></span>(<span>self, api_client)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_list_nodes_no_body(self, api_client):
|
||||
"""No body returns all nodes."""
|
||||
response = api_client.post("/list_nodes",
|
||||
data="",
|
||||
content_type="application/json")
|
||||
data = response.get_json()
|
||||
assert isinstance(data, list)</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>No body returns all nodes.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_api.TestListNodes.test_list_nodes_no_filter"><code class="name flex">
|
||||
<span>def <span class="ident">test_list_nodes_no_filter</span></span>(<span>self, api_client)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_list_nodes_no_filter(self, api_client):
|
||||
response = api_client.post("/list_nodes", json={})
|
||||
data = response.get_json()
|
||||
assert response.status_code == 200
|
||||
assert isinstance(data, list)
|
||||
assert "router1" in data</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_api.TestListNodes.test_list_nodes_with_filter"><code class="name flex">
|
||||
<span>def <span class="ident">test_list_nodes_with_filter</span></span>(<span>self, api_client)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_list_nodes_with_filter(self, api_client):
|
||||
response = api_client.post("/list_nodes", json={"filter": "router.*"})
|
||||
data = response.get_json()
|
||||
assert "router1" in data
|
||||
assert all("router" in n or "Router" in n for n in data)</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_api.TestRootEndpoint"><code class="flex name class">
|
||||
<span>class <span class="ident">TestRootEndpoint</span></span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class TestRootEndpoint:
|
||||
def test_root_returns_welcome(self, api_client):
|
||||
response = api_client.get("/")
|
||||
data = response.get_json()
|
||||
assert response.status_code == 200
|
||||
assert "Welcome" in data["message"]
|
||||
assert "version" in data</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="connpy.tests.test_api.TestRootEndpoint.test_root_returns_welcome"><code class="name flex">
|
||||
<span>def <span class="ident">test_root_returns_welcome</span></span>(<span>self, api_client)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_root_returns_welcome(self, api_client):
|
||||
response = api_client.get("/")
|
||||
data = response.get_json()
|
||||
assert response.status_code == 200
|
||||
assert "Welcome" in data["message"]
|
||||
assert "version" in data</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_api.TestRunCommands"><code class="flex name class">
|
||||
<span>class <span class="ident">TestRunCommands</span></span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class TestRunCommands:
|
||||
def test_missing_action(self, api_client):
|
||||
response = api_client.post("/run_commands", json={
|
||||
"nodes": "router1",
|
||||
"commands": ["show version"]
|
||||
})
|
||||
data = response.get_json()
|
||||
assert "DataError" in data
|
||||
assert "action" in data["DataError"]
|
||||
|
||||
def test_missing_nodes(self, api_client):
|
||||
response = api_client.post("/run_commands", json={
|
||||
"action": "run",
|
||||
"commands": ["show version"]
|
||||
})
|
||||
data = response.get_json()
|
||||
assert "DataError" in data
|
||||
assert "nodes" in data["DataError"]
|
||||
|
||||
def test_missing_commands(self, api_client):
|
||||
response = api_client.post("/run_commands", json={
|
||||
"action": "run",
|
||||
"nodes": "router1"
|
||||
})
|
||||
data = response.get_json()
|
||||
assert "DataError" in data
|
||||
assert "commands" in data["DataError"]
|
||||
|
||||
def test_wrong_action(self, api_client):
|
||||
response = api_client.post("/run_commands", json={
|
||||
"action": "invalid",
|
||||
"nodes": "router1",
|
||||
"commands": ["show version"]
|
||||
})
|
||||
data = response.get_json()
|
||||
assert "DataError" in data
|
||||
assert "Wrong action" in data["DataError"]
|
||||
|
||||
@patch("connpy.api.nodes")
|
||||
def test_run_action(self, mock_nodes_cls, api_client):
|
||||
"""action=run executes and returns output."""
|
||||
mock_instance = MagicMock()
|
||||
mock_instance.run.return_value = {"router1": "Router v1.0"}
|
||||
mock_nodes_cls.return_value = mock_instance
|
||||
|
||||
response = api_client.post("/run_commands", json={
|
||||
"action": "run",
|
||||
"nodes": "router1",
|
||||
"commands": ["show version"]
|
||||
})
|
||||
data = response.get_json()
|
||||
assert "router1" in data
|
||||
|
||||
@patch("connpy.api.nodes")
|
||||
def test_test_action(self, mock_nodes_cls, api_client):
|
||||
"""action=test returns result + output."""
|
||||
mock_instance = MagicMock()
|
||||
mock_instance.test.return_value = {"router1": {"expected": True}}
|
||||
mock_instance.output = {"router1": "output text"}
|
||||
mock_nodes_cls.return_value = mock_instance
|
||||
|
||||
response = api_client.post("/run_commands", json={
|
||||
"action": "test",
|
||||
"nodes": "router1",
|
||||
"commands": ["show version"],
|
||||
"expected": "Router"
|
||||
})
|
||||
data = response.get_json()
|
||||
assert "result" in data
|
||||
assert "output" in data
|
||||
|
||||
@patch("connpy.api.nodes")
|
||||
def test_run_with_options(self, mock_nodes_cls, api_client):
|
||||
"""Options get passed through."""
|
||||
mock_instance = MagicMock()
|
||||
mock_instance.run.return_value = {"router1": "ok"}
|
||||
mock_nodes_cls.return_value = mock_instance
|
||||
|
||||
response = api_client.post("/run_commands", json={
|
||||
"action": "run",
|
||||
"nodes": "router1",
|
||||
"commands": ["show version"],
|
||||
"options": {"timeout": 30, "parallel": 5}
|
||||
})
|
||||
assert response.status_code == 200
|
||||
|
||||
@patch("connpy.api.nodes")
|
||||
def test_run_folder_nodes(self, mock_nodes_cls, api_client):
|
||||
"""Nodes with @ prefix are resolved as folders."""
|
||||
mock_instance = MagicMock()
|
||||
mock_instance.run.return_value = {"server1@office": "ok"}
|
||||
mock_nodes_cls.return_value = mock_instance
|
||||
|
||||
response = api_client.post("/run_commands", json={
|
||||
"action": "run",
|
||||
"nodes": "@office",
|
||||
"commands": ["ls -la"]
|
||||
})
|
||||
assert response.status_code == 200
|
||||
|
||||
@patch("connpy.api.nodes")
|
||||
def test_run_list_nodes(self, mock_nodes_cls, api_client):
|
||||
"""List of nodes is resolved correctly."""
|
||||
mock_instance = MagicMock()
|
||||
mock_instance.run.return_value = {"router1": "ok", "server1@office": "ok"}
|
||||
mock_nodes_cls.return_value = mock_instance
|
||||
|
||||
response = api_client.post("/run_commands", json={
|
||||
"action": "run",
|
||||
"nodes": ["router1", "server1@office"],
|
||||
"commands": ["show version"]
|
||||
})
|
||||
assert response.status_code == 200</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="connpy.tests.test_api.TestRunCommands.test_missing_action"><code class="name flex">
|
||||
<span>def <span class="ident">test_missing_action</span></span>(<span>self, api_client)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_missing_action(self, api_client):
|
||||
response = api_client.post("/run_commands", json={
|
||||
"nodes": "router1",
|
||||
"commands": ["show version"]
|
||||
})
|
||||
data = response.get_json()
|
||||
assert "DataError" in data
|
||||
assert "action" in data["DataError"]</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_api.TestRunCommands.test_missing_commands"><code class="name flex">
|
||||
<span>def <span class="ident">test_missing_commands</span></span>(<span>self, api_client)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_missing_commands(self, api_client):
|
||||
response = api_client.post("/run_commands", json={
|
||||
"action": "run",
|
||||
"nodes": "router1"
|
||||
})
|
||||
data = response.get_json()
|
||||
assert "DataError" in data
|
||||
assert "commands" in data["DataError"]</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_api.TestRunCommands.test_missing_nodes"><code class="name flex">
|
||||
<span>def <span class="ident">test_missing_nodes</span></span>(<span>self, api_client)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_missing_nodes(self, api_client):
|
||||
response = api_client.post("/run_commands", json={
|
||||
"action": "run",
|
||||
"commands": ["show version"]
|
||||
})
|
||||
data = response.get_json()
|
||||
assert "DataError" in data
|
||||
assert "nodes" in data["DataError"]</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_api.TestRunCommands.test_run_action"><code class="name flex">
|
||||
<span>def <span class="ident">test_run_action</span></span>(<span>self, mock_nodes_cls, api_client)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@patch("connpy.api.nodes")
|
||||
def test_run_action(self, mock_nodes_cls, api_client):
|
||||
"""action=run executes and returns output."""
|
||||
mock_instance = MagicMock()
|
||||
mock_instance.run.return_value = {"router1": "Router v1.0"}
|
||||
mock_nodes_cls.return_value = mock_instance
|
||||
|
||||
response = api_client.post("/run_commands", json={
|
||||
"action": "run",
|
||||
"nodes": "router1",
|
||||
"commands": ["show version"]
|
||||
})
|
||||
data = response.get_json()
|
||||
assert "router1" in data</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>action=run executes and returns output.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_api.TestRunCommands.test_run_folder_nodes"><code class="name flex">
|
||||
<span>def <span class="ident">test_run_folder_nodes</span></span>(<span>self, mock_nodes_cls, api_client)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@patch("connpy.api.nodes")
|
||||
def test_run_folder_nodes(self, mock_nodes_cls, api_client):
|
||||
"""Nodes with @ prefix are resolved as folders."""
|
||||
mock_instance = MagicMock()
|
||||
mock_instance.run.return_value = {"server1@office": "ok"}
|
||||
mock_nodes_cls.return_value = mock_instance
|
||||
|
||||
response = api_client.post("/run_commands", json={
|
||||
"action": "run",
|
||||
"nodes": "@office",
|
||||
"commands": ["ls -la"]
|
||||
})
|
||||
assert response.status_code == 200</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Nodes with @ prefix are resolved as folders.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_api.TestRunCommands.test_run_list_nodes"><code class="name flex">
|
||||
<span>def <span class="ident">test_run_list_nodes</span></span>(<span>self, mock_nodes_cls, api_client)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@patch("connpy.api.nodes")
|
||||
def test_run_list_nodes(self, mock_nodes_cls, api_client):
|
||||
"""List of nodes is resolved correctly."""
|
||||
mock_instance = MagicMock()
|
||||
mock_instance.run.return_value = {"router1": "ok", "server1@office": "ok"}
|
||||
mock_nodes_cls.return_value = mock_instance
|
||||
|
||||
response = api_client.post("/run_commands", json={
|
||||
"action": "run",
|
||||
"nodes": ["router1", "server1@office"],
|
||||
"commands": ["show version"]
|
||||
})
|
||||
assert response.status_code == 200</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>List of nodes is resolved correctly.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_api.TestRunCommands.test_run_with_options"><code class="name flex">
|
||||
<span>def <span class="ident">test_run_with_options</span></span>(<span>self, mock_nodes_cls, api_client)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@patch("connpy.api.nodes")
|
||||
def test_run_with_options(self, mock_nodes_cls, api_client):
|
||||
"""Options get passed through."""
|
||||
mock_instance = MagicMock()
|
||||
mock_instance.run.return_value = {"router1": "ok"}
|
||||
mock_nodes_cls.return_value = mock_instance
|
||||
|
||||
response = api_client.post("/run_commands", json={
|
||||
"action": "run",
|
||||
"nodes": "router1",
|
||||
"commands": ["show version"],
|
||||
"options": {"timeout": 30, "parallel": 5}
|
||||
})
|
||||
assert response.status_code == 200</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Options get passed through.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_api.TestRunCommands.test_test_action"><code class="name flex">
|
||||
<span>def <span class="ident">test_test_action</span></span>(<span>self, mock_nodes_cls, api_client)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">@patch("connpy.api.nodes")
|
||||
def test_test_action(self, mock_nodes_cls, api_client):
|
||||
"""action=test returns result + output."""
|
||||
mock_instance = MagicMock()
|
||||
mock_instance.test.return_value = {"router1": {"expected": True}}
|
||||
mock_instance.output = {"router1": "output text"}
|
||||
mock_nodes_cls.return_value = mock_instance
|
||||
|
||||
response = api_client.post("/run_commands", json={
|
||||
"action": "test",
|
||||
"nodes": "router1",
|
||||
"commands": ["show version"],
|
||||
"expected": "Router"
|
||||
})
|
||||
data = response.get_json()
|
||||
assert "result" in data
|
||||
assert "output" in data</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>action=test returns result + output.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_api.TestRunCommands.test_wrong_action"><code class="name flex">
|
||||
<span>def <span class="ident">test_wrong_action</span></span>(<span>self, api_client)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_wrong_action(self, api_client):
|
||||
response = api_client.post("/run_commands", json={
|
||||
"action": "invalid",
|
||||
"nodes": "router1",
|
||||
"commands": ["show version"]
|
||||
})
|
||||
data = response.get_json()
|
||||
assert "DataError" in data
|
||||
assert "Wrong action" in data["DataError"]</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-functions">Functions</a></h3>
|
||||
<ul class="">
|
||||
<li><code><a title="connpy.tests.test_api.api_client" href="#connpy.tests.test_api.api_client">api_client</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><h3><a href="#header-classes">Classes</a></h3>
|
||||
<ul>
|
||||
<li>
|
||||
<h4><code><a title="connpy.tests.test_api.TestAskAI" href="#connpy.tests.test_api.TestAskAI">TestAskAI</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="connpy.tests.test_api.TestAskAI.test_ask_ai" href="#connpy.tests.test_api.TestAskAI.test_ask_ai">test_ask_ai</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_api.TestAskAI.test_ask_ai_with_dryrun" href="#connpy.tests.test_api.TestAskAI.test_ask_ai_with_dryrun">test_ask_ai_with_dryrun</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_api.TestAskAI.test_ask_ai_with_history" href="#connpy.tests.test_api.TestAskAI.test_ask_ai_with_history">test_ask_ai_with_history</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h4><code><a title="connpy.tests.test_api.TestConfirm" href="#connpy.tests.test_api.TestConfirm">TestConfirm</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="connpy.tests.test_api.TestConfirm.test_confirm" href="#connpy.tests.test_api.TestConfirm.test_confirm">test_confirm</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h4><code><a title="connpy.tests.test_api.TestGetNodes" href="#connpy.tests.test_api.TestGetNodes">TestGetNodes</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="connpy.tests.test_api.TestGetNodes.test_get_nodes_has_attributes" href="#connpy.tests.test_api.TestGetNodes.test_get_nodes_has_attributes">test_get_nodes_has_attributes</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_api.TestGetNodes.test_get_nodes_no_filter" href="#connpy.tests.test_api.TestGetNodes.test_get_nodes_no_filter">test_get_nodes_no_filter</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_api.TestGetNodes.test_get_nodes_with_filter" href="#connpy.tests.test_api.TestGetNodes.test_get_nodes_with_filter">test_get_nodes_with_filter</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h4><code><a title="connpy.tests.test_api.TestListNodes" href="#connpy.tests.test_api.TestListNodes">TestListNodes</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="connpy.tests.test_api.TestListNodes.test_list_nodes_case_insensitive" href="#connpy.tests.test_api.TestListNodes.test_list_nodes_case_insensitive">test_list_nodes_case_insensitive</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_api.TestListNodes.test_list_nodes_no_body" href="#connpy.tests.test_api.TestListNodes.test_list_nodes_no_body">test_list_nodes_no_body</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_api.TestListNodes.test_list_nodes_no_filter" href="#connpy.tests.test_api.TestListNodes.test_list_nodes_no_filter">test_list_nodes_no_filter</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_api.TestListNodes.test_list_nodes_with_filter" href="#connpy.tests.test_api.TestListNodes.test_list_nodes_with_filter">test_list_nodes_with_filter</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h4><code><a title="connpy.tests.test_api.TestRootEndpoint" href="#connpy.tests.test_api.TestRootEndpoint">TestRootEndpoint</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="connpy.tests.test_api.TestRootEndpoint.test_root_returns_welcome" href="#connpy.tests.test_api.TestRootEndpoint.test_root_returns_welcome">test_root_returns_welcome</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h4><code><a title="connpy.tests.test_api.TestRunCommands" href="#connpy.tests.test_api.TestRunCommands">TestRunCommands</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="connpy.tests.test_api.TestRunCommands.test_missing_action" href="#connpy.tests.test_api.TestRunCommands.test_missing_action">test_missing_action</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_api.TestRunCommands.test_missing_commands" href="#connpy.tests.test_api.TestRunCommands.test_missing_commands">test_missing_commands</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_api.TestRunCommands.test_missing_nodes" href="#connpy.tests.test_api.TestRunCommands.test_missing_nodes">test_missing_nodes</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_api.TestRunCommands.test_run_action" href="#connpy.tests.test_api.TestRunCommands.test_run_action">test_run_action</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_api.TestRunCommands.test_run_folder_nodes" href="#connpy.tests.test_api.TestRunCommands.test_run_folder_nodes">test_run_folder_nodes</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_api.TestRunCommands.test_run_list_nodes" href="#connpy.tests.test_api.TestRunCommands.test_run_list_nodes">test_run_list_nodes</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_api.TestRunCommands.test_run_with_options" href="#connpy.tests.test_api.TestRunCommands.test_run_with_options">test_run_with_options</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_api.TestRunCommands.test_test_action" href="#connpy.tests.test_api.TestRunCommands.test_test_action">test_test_action</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_api.TestRunCommands.test_wrong_action" href="#connpy.tests.test_api.TestRunCommands.test_wrong_action">test_wrong_action</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,610 @@
|
||||
<!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_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>
|
||||
<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_completion</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<p>Tests for connpy.completion module.</p>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-classes">Classes</h2>
|
||||
<dl>
|
||||
<dt id="connpy.tests.test_completion.TestGetAllFolders"><code class="flex name class">
|
||||
<span>class <span class="ident">TestGetAllFolders</span></span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class TestGetAllFolders:
|
||||
def test_basic_folders(self):
|
||||
config = {
|
||||
"connections": {
|
||||
"office": {"type": "folder"},
|
||||
"home": {"type": "folder"}
|
||||
}
|
||||
}
|
||||
folders = _getallfolders(config)
|
||||
assert "@office" in folders
|
||||
assert "@home" in folders
|
||||
|
||||
def test_with_subfolders(self):
|
||||
config = {
|
||||
"connections": {
|
||||
"office": {
|
||||
"type": "folder",
|
||||
"datacenter": {"type": "subfolder"},
|
||||
"server1": {"type": "connection"}
|
||||
}
|
||||
}
|
||||
}
|
||||
folders = _getallfolders(config)
|
||||
assert "@office" in folders
|
||||
assert "@datacenter@office" in folders
|
||||
|
||||
def test_empty(self):
|
||||
config = {"connections": {}}
|
||||
folders = _getallfolders(config)
|
||||
assert folders == []</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="connpy.tests.test_completion.TestGetAllFolders.test_basic_folders"><code class="name flex">
|
||||
<span>def <span class="ident">test_basic_folders</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_basic_folders(self):
|
||||
config = {
|
||||
"connections": {
|
||||
"office": {"type": "folder"},
|
||||
"home": {"type": "folder"}
|
||||
}
|
||||
}
|
||||
folders = _getallfolders(config)
|
||||
assert "@office" in folders
|
||||
assert "@home" in folders</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_completion.TestGetAllFolders.test_empty"><code class="name flex">
|
||||
<span>def <span class="ident">test_empty</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_empty(self):
|
||||
config = {"connections": {}}
|
||||
folders = _getallfolders(config)
|
||||
assert folders == []</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_completion.TestGetAllFolders.test_with_subfolders"><code class="name flex">
|
||||
<span>def <span class="ident">test_with_subfolders</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_with_subfolders(self):
|
||||
config = {
|
||||
"connections": {
|
||||
"office": {
|
||||
"type": "folder",
|
||||
"datacenter": {"type": "subfolder"},
|
||||
"server1": {"type": "connection"}
|
||||
}
|
||||
}
|
||||
}
|
||||
folders = _getallfolders(config)
|
||||
assert "@office" in folders
|
||||
assert "@datacenter@office" in folders</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_completion.TestGetAllNodes"><code class="flex name class">
|
||||
<span>class <span class="ident">TestGetAllNodes</span></span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class TestGetAllNodes:
|
||||
def test_flat_nodes(self):
|
||||
"""Nodes without folders."""
|
||||
config = {
|
||||
"connections": {
|
||||
"router1": {"type": "connection"},
|
||||
"router2": {"type": "connection"}
|
||||
}
|
||||
}
|
||||
nodes = _getallnodes(config)
|
||||
assert "router1" in nodes
|
||||
assert "router2" in nodes
|
||||
|
||||
def test_nested_nodes(self):
|
||||
"""Nodes in folders and subfolders have correct format."""
|
||||
config = {
|
||||
"connections": {
|
||||
"router1": {"type": "connection"},
|
||||
"office": {
|
||||
"type": "folder",
|
||||
"server1": {"type": "connection"},
|
||||
"datacenter": {
|
||||
"type": "subfolder",
|
||||
"db1": {"type": "connection"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
nodes = _getallnodes(config)
|
||||
assert "router1" in nodes
|
||||
assert "server1@office" in nodes
|
||||
assert "db1@datacenter@office" in nodes
|
||||
|
||||
def test_empty_connections(self):
|
||||
config = {"connections": {}}
|
||||
nodes = _getallnodes(config)
|
||||
assert nodes == []</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="connpy.tests.test_completion.TestGetAllNodes.test_empty_connections"><code class="name flex">
|
||||
<span>def <span class="ident">test_empty_connections</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_empty_connections(self):
|
||||
config = {"connections": {}}
|
||||
nodes = _getallnodes(config)
|
||||
assert nodes == []</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_completion.TestGetAllNodes.test_flat_nodes"><code class="name flex">
|
||||
<span>def <span class="ident">test_flat_nodes</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_flat_nodes(self):
|
||||
"""Nodes without folders."""
|
||||
config = {
|
||||
"connections": {
|
||||
"router1": {"type": "connection"},
|
||||
"router2": {"type": "connection"}
|
||||
}
|
||||
}
|
||||
nodes = _getallnodes(config)
|
||||
assert "router1" in nodes
|
||||
assert "router2" in nodes</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Nodes without folders.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_completion.TestGetAllNodes.test_nested_nodes"><code class="name flex">
|
||||
<span>def <span class="ident">test_nested_nodes</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_nested_nodes(self):
|
||||
"""Nodes in folders and subfolders have correct format."""
|
||||
config = {
|
||||
"connections": {
|
||||
"router1": {"type": "connection"},
|
||||
"office": {
|
||||
"type": "folder",
|
||||
"server1": {"type": "connection"},
|
||||
"datacenter": {
|
||||
"type": "subfolder",
|
||||
"db1": {"type": "connection"}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
nodes = _getallnodes(config)
|
||||
assert "router1" in nodes
|
||||
assert "server1@office" in nodes
|
||||
assert "db1@datacenter@office" in nodes</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Nodes in folders and subfolders have correct format.</p></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_completion.TestGetCwd"><code class="flex name class">
|
||||
<span>class <span class="ident">TestGetCwd</span></span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class TestGetCwd:
|
||||
def test_current_dir(self, tmp_path, monkeypatch):
|
||||
"""Lists files in current directory."""
|
||||
monkeypatch.chdir(tmp_path)
|
||||
(tmp_path / "file1.txt").touch()
|
||||
(tmp_path / "file2.py").touch()
|
||||
subdir = tmp_path / "subdir"
|
||||
subdir.mkdir()
|
||||
|
||||
result = _getcwd(["run", "run"], "run")
|
||||
# Should list files
|
||||
assert any("file1.txt" in r for r in result)
|
||||
assert any("subdir/" in r for r in result)
|
||||
|
||||
def test_specific_path(self, tmp_path, monkeypatch):
|
||||
"""Lists files matching a partial path."""
|
||||
monkeypatch.chdir(tmp_path)
|
||||
(tmp_path / "script.yaml").touch()
|
||||
(tmp_path / "script2.yaml").touch()
|
||||
|
||||
result = _getcwd(["run", "script"], "run")
|
||||
assert any("script" in r for r in result)
|
||||
|
||||
def test_folder_only(self, tmp_path, monkeypatch):
|
||||
"""folderonly=True returns only directories."""
|
||||
monkeypatch.chdir(tmp_path)
|
||||
(tmp_path / "file.txt").touch()
|
||||
subdir = tmp_path / "mydir"
|
||||
subdir.mkdir()
|
||||
|
||||
result = _getcwd(["export", "export"], "export", folderonly=True)
|
||||
files_in_result = [r for r in result if "file.txt" in r]
|
||||
assert len(files_in_result) == 0
|
||||
dirs_in_result = [r for r in result if "mydir" in r]
|
||||
assert len(dirs_in_result) > 0</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="connpy.tests.test_completion.TestGetCwd.test_current_dir"><code class="name flex">
|
||||
<span>def <span class="ident">test_current_dir</span></span>(<span>self, tmp_path, monkeypatch)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_current_dir(self, tmp_path, monkeypatch):
|
||||
"""Lists files in current directory."""
|
||||
monkeypatch.chdir(tmp_path)
|
||||
(tmp_path / "file1.txt").touch()
|
||||
(tmp_path / "file2.py").touch()
|
||||
subdir = tmp_path / "subdir"
|
||||
subdir.mkdir()
|
||||
|
||||
result = _getcwd(["run", "run"], "run")
|
||||
# Should list files
|
||||
assert any("file1.txt" in r for r in result)
|
||||
assert any("subdir/" in r for r in result)</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Lists files in current directory.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_completion.TestGetCwd.test_folder_only"><code class="name flex">
|
||||
<span>def <span class="ident">test_folder_only</span></span>(<span>self, tmp_path, monkeypatch)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_folder_only(self, tmp_path, monkeypatch):
|
||||
"""folderonly=True returns only directories."""
|
||||
monkeypatch.chdir(tmp_path)
|
||||
(tmp_path / "file.txt").touch()
|
||||
subdir = tmp_path / "mydir"
|
||||
subdir.mkdir()
|
||||
|
||||
result = _getcwd(["export", "export"], "export", folderonly=True)
|
||||
files_in_result = [r for r in result if "file.txt" in r]
|
||||
assert len(files_in_result) == 0
|
||||
dirs_in_result = [r for r in result if "mydir" in r]
|
||||
assert len(dirs_in_result) > 0</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>folderonly=True returns only directories.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_completion.TestGetCwd.test_specific_path"><code class="name flex">
|
||||
<span>def <span class="ident">test_specific_path</span></span>(<span>self, tmp_path, monkeypatch)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_specific_path(self, tmp_path, monkeypatch):
|
||||
"""Lists files matching a partial path."""
|
||||
monkeypatch.chdir(tmp_path)
|
||||
(tmp_path / "script.yaml").touch()
|
||||
(tmp_path / "script2.yaml").touch()
|
||||
|
||||
result = _getcwd(["run", "script"], "run")
|
||||
assert any("script" in r for r in result)</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Lists files matching a partial path.</p></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_completion.TestGetPlugins"><code class="flex name class">
|
||||
<span>class <span class="ident">TestGetPlugins</span></span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class TestGetPlugins:
|
||||
def test_get_plugins_disable(self, tmp_path):
|
||||
"""--disable returns enabled plugins."""
|
||||
plugin_dir = tmp_path / "plugins"
|
||||
plugin_dir.mkdir()
|
||||
(plugin_dir / "active.py").touch()
|
||||
(plugin_dir / "disabled.py.bkp").touch()
|
||||
|
||||
result = _get_plugins("--disable", str(tmp_path))
|
||||
assert "active" in result
|
||||
assert "disabled" not in result
|
||||
|
||||
def test_get_plugins_enable(self, tmp_path):
|
||||
"""--enable returns disabled plugins."""
|
||||
plugin_dir = tmp_path / "plugins"
|
||||
plugin_dir.mkdir()
|
||||
(plugin_dir / "active.py").touch()
|
||||
(plugin_dir / "disabled.py.bkp").touch()
|
||||
|
||||
result = _get_plugins("--enable", str(tmp_path))
|
||||
assert "disabled" in result
|
||||
assert "active" not in result
|
||||
|
||||
def test_get_plugins_del(self, tmp_path):
|
||||
"""--del returns all plugins."""
|
||||
plugin_dir = tmp_path / "plugins"
|
||||
plugin_dir.mkdir()
|
||||
(plugin_dir / "active.py").touch()
|
||||
(plugin_dir / "disabled.py.bkp").touch()
|
||||
|
||||
result = _get_plugins("--del", str(tmp_path))
|
||||
assert "active" in result
|
||||
assert "disabled" in result
|
||||
|
||||
def test_get_plugins_all(self, tmp_path):
|
||||
"""'all' returns dict with paths."""
|
||||
plugin_dir = tmp_path / "plugins"
|
||||
plugin_dir.mkdir()
|
||||
(plugin_dir / "myplugin.py").touch()
|
||||
|
||||
result = _get_plugins("all", str(tmp_path))
|
||||
assert isinstance(result, dict)
|
||||
assert "myplugin" in result
|
||||
|
||||
def test_get_plugins_empty_dir(self, tmp_path):
|
||||
"""Empty plugins directory returns empty list."""
|
||||
plugin_dir = tmp_path / "plugins"
|
||||
plugin_dir.mkdir()
|
||||
|
||||
result = _get_plugins("--disable", str(tmp_path))
|
||||
assert result == []</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="connpy.tests.test_completion.TestGetPlugins.test_get_plugins_all"><code class="name flex">
|
||||
<span>def <span class="ident">test_get_plugins_all</span></span>(<span>self, tmp_path)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_get_plugins_all(self, tmp_path):
|
||||
"""'all' returns dict with paths."""
|
||||
plugin_dir = tmp_path / "plugins"
|
||||
plugin_dir.mkdir()
|
||||
(plugin_dir / "myplugin.py").touch()
|
||||
|
||||
result = _get_plugins("all", str(tmp_path))
|
||||
assert isinstance(result, dict)
|
||||
assert "myplugin" in result</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>'all' returns dict with paths.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_completion.TestGetPlugins.test_get_plugins_del"><code class="name flex">
|
||||
<span>def <span class="ident">test_get_plugins_del</span></span>(<span>self, tmp_path)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_get_plugins_del(self, tmp_path):
|
||||
"""--del returns all plugins."""
|
||||
plugin_dir = tmp_path / "plugins"
|
||||
plugin_dir.mkdir()
|
||||
(plugin_dir / "active.py").touch()
|
||||
(plugin_dir / "disabled.py.bkp").touch()
|
||||
|
||||
result = _get_plugins("--del", str(tmp_path))
|
||||
assert "active" in result
|
||||
assert "disabled" in result</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>–del returns all plugins.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_completion.TestGetPlugins.test_get_plugins_disable"><code class="name flex">
|
||||
<span>def <span class="ident">test_get_plugins_disable</span></span>(<span>self, tmp_path)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_get_plugins_disable(self, tmp_path):
|
||||
"""--disable returns enabled plugins."""
|
||||
plugin_dir = tmp_path / "plugins"
|
||||
plugin_dir.mkdir()
|
||||
(plugin_dir / "active.py").touch()
|
||||
(plugin_dir / "disabled.py.bkp").touch()
|
||||
|
||||
result = _get_plugins("--disable", str(tmp_path))
|
||||
assert "active" in result
|
||||
assert "disabled" not in result</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>–disable returns enabled plugins.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_completion.TestGetPlugins.test_get_plugins_empty_dir"><code class="name flex">
|
||||
<span>def <span class="ident">test_get_plugins_empty_dir</span></span>(<span>self, tmp_path)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_get_plugins_empty_dir(self, tmp_path):
|
||||
"""Empty plugins directory returns empty list."""
|
||||
plugin_dir = tmp_path / "plugins"
|
||||
plugin_dir.mkdir()
|
||||
|
||||
result = _get_plugins("--disable", str(tmp_path))
|
||||
assert result == []</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Empty plugins directory returns empty list.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_completion.TestGetPlugins.test_get_plugins_enable"><code class="name flex">
|
||||
<span>def <span class="ident">test_get_plugins_enable</span></span>(<span>self, tmp_path)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_get_plugins_enable(self, tmp_path):
|
||||
"""--enable returns disabled plugins."""
|
||||
plugin_dir = tmp_path / "plugins"
|
||||
plugin_dir.mkdir()
|
||||
(plugin_dir / "active.py").touch()
|
||||
(plugin_dir / "disabled.py.bkp").touch()
|
||||
|
||||
result = _get_plugins("--enable", str(tmp_path))
|
||||
assert "disabled" in result
|
||||
assert "active" not in result</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>–enable returns disabled plugins.</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.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_completion.TestGetAllFolders" href="#connpy.tests.test_completion.TestGetAllFolders">TestGetAllFolders</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="connpy.tests.test_completion.TestGetAllFolders.test_basic_folders" href="#connpy.tests.test_completion.TestGetAllFolders.test_basic_folders">test_basic_folders</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_completion.TestGetAllFolders.test_empty" href="#connpy.tests.test_completion.TestGetAllFolders.test_empty">test_empty</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_completion.TestGetAllFolders.test_with_subfolders" href="#connpy.tests.test_completion.TestGetAllFolders.test_with_subfolders">test_with_subfolders</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h4><code><a title="connpy.tests.test_completion.TestGetAllNodes" href="#connpy.tests.test_completion.TestGetAllNodes">TestGetAllNodes</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="connpy.tests.test_completion.TestGetAllNodes.test_empty_connections" href="#connpy.tests.test_completion.TestGetAllNodes.test_empty_connections">test_empty_connections</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_completion.TestGetAllNodes.test_flat_nodes" href="#connpy.tests.test_completion.TestGetAllNodes.test_flat_nodes">test_flat_nodes</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_completion.TestGetAllNodes.test_nested_nodes" href="#connpy.tests.test_completion.TestGetAllNodes.test_nested_nodes">test_nested_nodes</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h4><code><a title="connpy.tests.test_completion.TestGetCwd" href="#connpy.tests.test_completion.TestGetCwd">TestGetCwd</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="connpy.tests.test_completion.TestGetCwd.test_current_dir" href="#connpy.tests.test_completion.TestGetCwd.test_current_dir">test_current_dir</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_completion.TestGetCwd.test_folder_only" href="#connpy.tests.test_completion.TestGetCwd.test_folder_only">test_folder_only</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_completion.TestGetCwd.test_specific_path" href="#connpy.tests.test_completion.TestGetCwd.test_specific_path">test_specific_path</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h4><code><a title="connpy.tests.test_completion.TestGetPlugins" href="#connpy.tests.test_completion.TestGetPlugins">TestGetPlugins</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="connpy.tests.test_completion.TestGetPlugins.test_get_plugins_all" href="#connpy.tests.test_completion.TestGetPlugins.test_get_plugins_all">test_get_plugins_all</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_completion.TestGetPlugins.test_get_plugins_del" href="#connpy.tests.test_completion.TestGetPlugins.test_get_plugins_del">test_get_plugins_del</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_completion.TestGetPlugins.test_get_plugins_disable" href="#connpy.tests.test_completion.TestGetPlugins.test_get_plugins_disable">test_get_plugins_disable</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_completion.TestGetPlugins.test_get_plugins_empty_dir" href="#connpy.tests.test_completion.TestGetPlugins.test_get_plugins_empty_dir">test_get_plugins_empty_dir</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_completion.TestGetPlugins.test_get_plugins_enable" href="#connpy.tests.test_completion.TestGetPlugins.test_get_plugins_enable">test_get_plugins_enable</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>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,679 @@
|
||||
<!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_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>
|
||||
<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_hooks</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<p>Tests for connpy.hooks module — MethodHook and ClassHook.</p>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-classes">Classes</h2>
|
||||
<dl>
|
||||
<dt id="connpy.tests.test_hooks.TestClassHook"><code class="flex name class">
|
||||
<span>class <span class="ident">TestClassHook</span></span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class TestClassHook:
|
||||
def test_creates_instance(self):
|
||||
"""ClassHook still creates instances normally."""
|
||||
@ClassHook
|
||||
class MyClass:
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
obj = MyClass(42)
|
||||
assert obj.value == 42
|
||||
|
||||
def test_modify_future_instances(self):
|
||||
"""modify() affects all future instances."""
|
||||
@ClassHook
|
||||
class MyClass:
|
||||
def __init__(self):
|
||||
self.x = 1
|
||||
|
||||
def set_x_to_99(instance):
|
||||
instance.x = 99
|
||||
|
||||
MyClass.modify(set_x_to_99)
|
||||
obj = MyClass()
|
||||
assert obj.x == 99
|
||||
|
||||
def test_modify_does_not_affect_past(self):
|
||||
"""modify() does not affect already-created instances."""
|
||||
@ClassHook
|
||||
class MyClass:
|
||||
def __init__(self):
|
||||
self.x = 1
|
||||
|
||||
old_obj = MyClass()
|
||||
|
||||
def set_x_to_99(instance):
|
||||
instance.x = 99
|
||||
|
||||
MyClass.modify(set_x_to_99)
|
||||
assert old_obj.x == 1 # Not affected
|
||||
assert MyClass().x == 99 # New instance IS affected
|
||||
|
||||
def test_instance_modify(self):
|
||||
"""instance.modify() only affects that specific instance."""
|
||||
@ClassHook
|
||||
class MyClass:
|
||||
def __init__(self):
|
||||
self.x = 1
|
||||
|
||||
obj1 = MyClass()
|
||||
obj2 = MyClass()
|
||||
|
||||
obj1.modify(lambda inst: setattr(inst, 'x', 999))
|
||||
assert obj1.x == 999
|
||||
assert obj2.x == 1
|
||||
|
||||
def test_multiple_deferred_hooks(self):
|
||||
"""Multiple modify() calls apply in order."""
|
||||
@ClassHook
|
||||
class MyClass:
|
||||
def __init__(self):
|
||||
self.log = []
|
||||
|
||||
MyClass.modify(lambda inst: inst.log.append("first"))
|
||||
MyClass.modify(lambda inst: inst.log.append("second"))
|
||||
|
||||
obj = MyClass()
|
||||
assert obj.log == ["first", "second"]
|
||||
|
||||
def test_getattr_delegation(self):
|
||||
"""ClassHook delegates attribute access to the wrapped class."""
|
||||
@ClassHook
|
||||
class MyClass:
|
||||
class_var = "hello"
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
assert MyClass.class_var == "hello"</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="connpy.tests.test_hooks.TestClassHook.test_creates_instance"><code class="name flex">
|
||||
<span>def <span class="ident">test_creates_instance</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_creates_instance(self):
|
||||
"""ClassHook still creates instances normally."""
|
||||
@ClassHook
|
||||
class MyClass:
|
||||
def __init__(self, value):
|
||||
self.value = value
|
||||
|
||||
obj = MyClass(42)
|
||||
assert obj.value == 42</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>ClassHook still creates instances normally.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_hooks.TestClassHook.test_getattr_delegation"><code class="name flex">
|
||||
<span>def <span class="ident">test_getattr_delegation</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_getattr_delegation(self):
|
||||
"""ClassHook delegates attribute access to the wrapped class."""
|
||||
@ClassHook
|
||||
class MyClass:
|
||||
class_var = "hello"
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
assert MyClass.class_var == "hello"</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>ClassHook delegates attribute access to the wrapped class.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_hooks.TestClassHook.test_instance_modify"><code class="name flex">
|
||||
<span>def <span class="ident">test_instance_modify</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_instance_modify(self):
|
||||
"""instance.modify() only affects that specific instance."""
|
||||
@ClassHook
|
||||
class MyClass:
|
||||
def __init__(self):
|
||||
self.x = 1
|
||||
|
||||
obj1 = MyClass()
|
||||
obj2 = MyClass()
|
||||
|
||||
obj1.modify(lambda inst: setattr(inst, 'x', 999))
|
||||
assert obj1.x == 999
|
||||
assert obj2.x == 1</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>instance.modify() only affects that specific instance.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_hooks.TestClassHook.test_modify_does_not_affect_past"><code class="name flex">
|
||||
<span>def <span class="ident">test_modify_does_not_affect_past</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_modify_does_not_affect_past(self):
|
||||
"""modify() does not affect already-created instances."""
|
||||
@ClassHook
|
||||
class MyClass:
|
||||
def __init__(self):
|
||||
self.x = 1
|
||||
|
||||
old_obj = MyClass()
|
||||
|
||||
def set_x_to_99(instance):
|
||||
instance.x = 99
|
||||
|
||||
MyClass.modify(set_x_to_99)
|
||||
assert old_obj.x == 1 # Not affected
|
||||
assert MyClass().x == 99 # New instance IS affected</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>modify() does not affect already-created instances.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_hooks.TestClassHook.test_modify_future_instances"><code class="name flex">
|
||||
<span>def <span class="ident">test_modify_future_instances</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_modify_future_instances(self):
|
||||
"""modify() affects all future instances."""
|
||||
@ClassHook
|
||||
class MyClass:
|
||||
def __init__(self):
|
||||
self.x = 1
|
||||
|
||||
def set_x_to_99(instance):
|
||||
instance.x = 99
|
||||
|
||||
MyClass.modify(set_x_to_99)
|
||||
obj = MyClass()
|
||||
assert obj.x == 99</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>modify() affects all future instances.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_hooks.TestClassHook.test_multiple_deferred_hooks"><code class="name flex">
|
||||
<span>def <span class="ident">test_multiple_deferred_hooks</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_multiple_deferred_hooks(self):
|
||||
"""Multiple modify() calls apply in order."""
|
||||
@ClassHook
|
||||
class MyClass:
|
||||
def __init__(self):
|
||||
self.log = []
|
||||
|
||||
MyClass.modify(lambda inst: inst.log.append("first"))
|
||||
MyClass.modify(lambda inst: inst.log.append("second"))
|
||||
|
||||
obj = MyClass()
|
||||
assert obj.log == ["first", "second"]</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Multiple modify() calls apply in order.</p></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_hooks.TestMethodHook"><code class="flex name class">
|
||||
<span>class <span class="ident">TestMethodHook</span></span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class TestMethodHook:
|
||||
def test_basic_call(self):
|
||||
"""Decorated function executes normally."""
|
||||
@MethodHook
|
||||
def add(a, b):
|
||||
return a + b
|
||||
assert add(2, 3) == 5
|
||||
|
||||
def test_pre_hook_modifies_args(self):
|
||||
"""Pre-hook can modify arguments before execution."""
|
||||
@MethodHook
|
||||
def greet(name):
|
||||
return f"Hello {name}"
|
||||
|
||||
def uppercase_hook(name):
|
||||
return (name.upper(),), {}
|
||||
|
||||
greet.register_pre_hook(uppercase_hook)
|
||||
assert greet("world") == "Hello WORLD"
|
||||
|
||||
def test_post_hook_modifies_result(self):
|
||||
"""Post-hook can modify the return value."""
|
||||
@MethodHook
|
||||
def compute(x):
|
||||
return x * 2
|
||||
|
||||
def double_result(*args, **kwargs):
|
||||
return kwargs["result"] * 2
|
||||
|
||||
compute.register_post_hook(double_result)
|
||||
assert compute(5) == 20 # 5*2=10, then 10*2=20
|
||||
|
||||
def test_multiple_pre_hooks_order(self):
|
||||
"""Pre-hooks execute in registration order."""
|
||||
calls = []
|
||||
|
||||
@MethodHook
|
||||
def func(x):
|
||||
return x
|
||||
|
||||
def hook1(x):
|
||||
calls.append("hook1")
|
||||
return (x,), {}
|
||||
|
||||
def hook2(x):
|
||||
calls.append("hook2")
|
||||
return (x,), {}
|
||||
|
||||
func.register_pre_hook(hook1)
|
||||
func.register_pre_hook(hook2)
|
||||
func(1)
|
||||
assert calls == ["hook1", "hook2"]
|
||||
|
||||
def test_multiple_post_hooks_order(self):
|
||||
"""Post-hooks execute in registration order."""
|
||||
calls = []
|
||||
|
||||
@MethodHook
|
||||
def func(x):
|
||||
return x
|
||||
|
||||
def hook1(*args, **kwargs):
|
||||
calls.append("hook1")
|
||||
return kwargs["result"]
|
||||
|
||||
def hook2(*args, **kwargs):
|
||||
calls.append("hook2")
|
||||
return kwargs["result"]
|
||||
|
||||
func.register_post_hook(hook1)
|
||||
func.register_post_hook(hook2)
|
||||
func(1)
|
||||
assert calls == ["hook1", "hook2"]
|
||||
|
||||
def test_pre_hook_exception_continues(self, capsys):
|
||||
"""If a pre-hook raises, the function still executes."""
|
||||
@MethodHook
|
||||
def func(x):
|
||||
return x + 1
|
||||
|
||||
def bad_hook(x):
|
||||
raise RuntimeError("broken hook")
|
||||
|
||||
func.register_pre_hook(bad_hook)
|
||||
# Should not raise — the hook error is printed but execution continues
|
||||
result = func(5)
|
||||
assert result == 6
|
||||
|
||||
def test_post_hook_exception_continues(self, capsys):
|
||||
"""If a post-hook raises, the result is still returned."""
|
||||
@MethodHook
|
||||
def func(x):
|
||||
return x + 1
|
||||
|
||||
def bad_hook(*args, **kwargs):
|
||||
raise RuntimeError("broken post hook")
|
||||
|
||||
func.register_post_hook(bad_hook)
|
||||
result = func(5)
|
||||
assert result == 6
|
||||
|
||||
def test_method_hook_as_instance_method(self):
|
||||
"""MethodHook works as a descriptor on a class."""
|
||||
class MyClass:
|
||||
@MethodHook
|
||||
def double(self, x):
|
||||
return x * 2
|
||||
|
||||
obj = MyClass()
|
||||
assert obj.double(5) == 10
|
||||
|
||||
def test_method_hook_instance_hook_registration(self):
|
||||
"""Can register hooks via instance method access."""
|
||||
class MyClass:
|
||||
@MethodHook
|
||||
def process(self, x):
|
||||
return x
|
||||
|
||||
def add_ten(*args, **kwargs):
|
||||
return kwargs["result"] + 10
|
||||
|
||||
obj = MyClass()
|
||||
obj.process.register_post_hook(add_ten)
|
||||
assert obj.process(5) == 15</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="connpy.tests.test_hooks.TestMethodHook.test_basic_call"><code class="name flex">
|
||||
<span>def <span class="ident">test_basic_call</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_basic_call(self):
|
||||
"""Decorated function executes normally."""
|
||||
@MethodHook
|
||||
def add(a, b):
|
||||
return a + b
|
||||
assert add(2, 3) == 5</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Decorated function executes normally.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_hooks.TestMethodHook.test_method_hook_as_instance_method"><code class="name flex">
|
||||
<span>def <span class="ident">test_method_hook_as_instance_method</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_method_hook_as_instance_method(self):
|
||||
"""MethodHook works as a descriptor on a class."""
|
||||
class MyClass:
|
||||
@MethodHook
|
||||
def double(self, x):
|
||||
return x * 2
|
||||
|
||||
obj = MyClass()
|
||||
assert obj.double(5) == 10</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>MethodHook works as a descriptor on a class.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_hooks.TestMethodHook.test_method_hook_instance_hook_registration"><code class="name flex">
|
||||
<span>def <span class="ident">test_method_hook_instance_hook_registration</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_method_hook_instance_hook_registration(self):
|
||||
"""Can register hooks via instance method access."""
|
||||
class MyClass:
|
||||
@MethodHook
|
||||
def process(self, x):
|
||||
return x
|
||||
|
||||
def add_ten(*args, **kwargs):
|
||||
return kwargs["result"] + 10
|
||||
|
||||
obj = MyClass()
|
||||
obj.process.register_post_hook(add_ten)
|
||||
assert obj.process(5) == 15</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Can register hooks via instance method access.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_hooks.TestMethodHook.test_multiple_post_hooks_order"><code class="name flex">
|
||||
<span>def <span class="ident">test_multiple_post_hooks_order</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_multiple_post_hooks_order(self):
|
||||
"""Post-hooks execute in registration order."""
|
||||
calls = []
|
||||
|
||||
@MethodHook
|
||||
def func(x):
|
||||
return x
|
||||
|
||||
def hook1(*args, **kwargs):
|
||||
calls.append("hook1")
|
||||
return kwargs["result"]
|
||||
|
||||
def hook2(*args, **kwargs):
|
||||
calls.append("hook2")
|
||||
return kwargs["result"]
|
||||
|
||||
func.register_post_hook(hook1)
|
||||
func.register_post_hook(hook2)
|
||||
func(1)
|
||||
assert calls == ["hook1", "hook2"]</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Post-hooks execute in registration order.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_hooks.TestMethodHook.test_multiple_pre_hooks_order"><code class="name flex">
|
||||
<span>def <span class="ident">test_multiple_pre_hooks_order</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_multiple_pre_hooks_order(self):
|
||||
"""Pre-hooks execute in registration order."""
|
||||
calls = []
|
||||
|
||||
@MethodHook
|
||||
def func(x):
|
||||
return x
|
||||
|
||||
def hook1(x):
|
||||
calls.append("hook1")
|
||||
return (x,), {}
|
||||
|
||||
def hook2(x):
|
||||
calls.append("hook2")
|
||||
return (x,), {}
|
||||
|
||||
func.register_pre_hook(hook1)
|
||||
func.register_pre_hook(hook2)
|
||||
func(1)
|
||||
assert calls == ["hook1", "hook2"]</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Pre-hooks execute in registration order.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_hooks.TestMethodHook.test_post_hook_exception_continues"><code class="name flex">
|
||||
<span>def <span class="ident">test_post_hook_exception_continues</span></span>(<span>self, capsys)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_post_hook_exception_continues(self, capsys):
|
||||
"""If a post-hook raises, the result is still returned."""
|
||||
@MethodHook
|
||||
def func(x):
|
||||
return x + 1
|
||||
|
||||
def bad_hook(*args, **kwargs):
|
||||
raise RuntimeError("broken post hook")
|
||||
|
||||
func.register_post_hook(bad_hook)
|
||||
result = func(5)
|
||||
assert result == 6</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>If a post-hook raises, the result is still returned.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_hooks.TestMethodHook.test_post_hook_modifies_result"><code class="name flex">
|
||||
<span>def <span class="ident">test_post_hook_modifies_result</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_post_hook_modifies_result(self):
|
||||
"""Post-hook can modify the return value."""
|
||||
@MethodHook
|
||||
def compute(x):
|
||||
return x * 2
|
||||
|
||||
def double_result(*args, **kwargs):
|
||||
return kwargs["result"] * 2
|
||||
|
||||
compute.register_post_hook(double_result)
|
||||
assert compute(5) == 20 # 5*2=10, then 10*2=20</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Post-hook can modify the return value.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_hooks.TestMethodHook.test_pre_hook_exception_continues"><code class="name flex">
|
||||
<span>def <span class="ident">test_pre_hook_exception_continues</span></span>(<span>self, capsys)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_pre_hook_exception_continues(self, capsys):
|
||||
"""If a pre-hook raises, the function still executes."""
|
||||
@MethodHook
|
||||
def func(x):
|
||||
return x + 1
|
||||
|
||||
def bad_hook(x):
|
||||
raise RuntimeError("broken hook")
|
||||
|
||||
func.register_pre_hook(bad_hook)
|
||||
# Should not raise — the hook error is printed but execution continues
|
||||
result = func(5)
|
||||
assert result == 6</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>If a pre-hook raises, the function still executes.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_hooks.TestMethodHook.test_pre_hook_modifies_args"><code class="name flex">
|
||||
<span>def <span class="ident">test_pre_hook_modifies_args</span></span>(<span>self)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_pre_hook_modifies_args(self):
|
||||
"""Pre-hook can modify arguments before execution."""
|
||||
@MethodHook
|
||||
def greet(name):
|
||||
return f"Hello {name}"
|
||||
|
||||
def uppercase_hook(name):
|
||||
return (name.upper(),), {}
|
||||
|
||||
greet.register_pre_hook(uppercase_hook)
|
||||
assert greet("world") == "Hello WORLD"</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Pre-hook can modify arguments before execution.</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.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_hooks.TestClassHook" href="#connpy.tests.test_hooks.TestClassHook">TestClassHook</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="connpy.tests.test_hooks.TestClassHook.test_creates_instance" href="#connpy.tests.test_hooks.TestClassHook.test_creates_instance">test_creates_instance</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_hooks.TestClassHook.test_getattr_delegation" href="#connpy.tests.test_hooks.TestClassHook.test_getattr_delegation">test_getattr_delegation</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_hooks.TestClassHook.test_instance_modify" href="#connpy.tests.test_hooks.TestClassHook.test_instance_modify">test_instance_modify</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_hooks.TestClassHook.test_modify_does_not_affect_past" href="#connpy.tests.test_hooks.TestClassHook.test_modify_does_not_affect_past">test_modify_does_not_affect_past</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_hooks.TestClassHook.test_modify_future_instances" href="#connpy.tests.test_hooks.TestClassHook.test_modify_future_instances">test_modify_future_instances</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_hooks.TestClassHook.test_multiple_deferred_hooks" href="#connpy.tests.test_hooks.TestClassHook.test_multiple_deferred_hooks">test_multiple_deferred_hooks</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h4><code><a title="connpy.tests.test_hooks.TestMethodHook" href="#connpy.tests.test_hooks.TestMethodHook">TestMethodHook</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="connpy.tests.test_hooks.TestMethodHook.test_basic_call" href="#connpy.tests.test_hooks.TestMethodHook.test_basic_call">test_basic_call</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_hooks.TestMethodHook.test_method_hook_as_instance_method" href="#connpy.tests.test_hooks.TestMethodHook.test_method_hook_as_instance_method">test_method_hook_as_instance_method</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_hooks.TestMethodHook.test_method_hook_instance_hook_registration" href="#connpy.tests.test_hooks.TestMethodHook.test_method_hook_instance_hook_registration">test_method_hook_instance_hook_registration</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_hooks.TestMethodHook.test_multiple_post_hooks_order" href="#connpy.tests.test_hooks.TestMethodHook.test_multiple_post_hooks_order">test_multiple_post_hooks_order</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_hooks.TestMethodHook.test_multiple_pre_hooks_order" href="#connpy.tests.test_hooks.TestMethodHook.test_multiple_pre_hooks_order">test_multiple_pre_hooks_order</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_hooks.TestMethodHook.test_post_hook_exception_continues" href="#connpy.tests.test_hooks.TestMethodHook.test_post_hook_exception_continues">test_post_hook_exception_continues</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_hooks.TestMethodHook.test_post_hook_modifies_result" href="#connpy.tests.test_hooks.TestMethodHook.test_post_hook_modifies_result">test_post_hook_modifies_result</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_hooks.TestMethodHook.test_pre_hook_exception_continues" href="#connpy.tests.test_hooks.TestMethodHook.test_pre_hook_exception_continues">test_pre_hook_exception_continues</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_hooks.TestMethodHook.test_pre_hook_modifies_args" href="#connpy.tests.test_hooks.TestMethodHook.test_pre_hook_modifies_args">test_pre_hook_modifies_args</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,923 @@
|
||||
<!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_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>
|
||||
<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_plugins</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<p>Tests for connpy.plugins module.</p>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-classes">Classes</h2>
|
||||
<dl>
|
||||
<dt id="connpy.tests.test_plugins.TestPluginLoading"><code class="flex name class">
|
||||
<span>class <span class="ident">TestPluginLoading</span></span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class TestPluginLoading:
|
||||
def test_import_from_path(self, tmp_path):
|
||||
p = tmp_path / "mymod.py"
|
||||
_write_plugin(p, """\
|
||||
MY_VAR = 42
|
||||
""")
|
||||
plugins = Plugins()
|
||||
module = plugins._import_from_path(str(p))
|
||||
assert module.MY_VAR == 42
|
||||
|
||||
def test_import_plugins_to_argparse(self, tmp_path):
|
||||
"""Valid plugins get loaded into argparse."""
|
||||
import argparse
|
||||
|
||||
plugin_dir = tmp_path / "plugins"
|
||||
plugin_dir.mkdir()
|
||||
_write_plugin(plugin_dir / "myplugin.py", """\
|
||||
import argparse
|
||||
|
||||
class Parser:
|
||||
def __init__(self):
|
||||
self.parser = argparse.ArgumentParser(description="My plugin")
|
||||
|
||||
class Entrypoint:
|
||||
def __init__(self, args, parser, connapp):
|
||||
pass
|
||||
""")
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
subparsers = parser.add_subparsers()
|
||||
|
||||
plugins = Plugins()
|
||||
plugins._import_plugins_to_argparse(str(plugin_dir), subparsers)
|
||||
|
||||
assert "myplugin" in plugins.plugins
|
||||
assert "myplugin" in plugins.plugin_parsers
|
||||
|
||||
def test_plugin_name_collision(self, tmp_path):
|
||||
"""Plugin with same name as existing subcommand is skipped."""
|
||||
import argparse
|
||||
|
||||
plugin_dir = tmp_path / "plugins"
|
||||
plugin_dir.mkdir()
|
||||
_write_plugin(plugin_dir / "existcmd.py", """\
|
||||
import argparse
|
||||
|
||||
class Parser:
|
||||
def __init__(self):
|
||||
self.parser = argparse.ArgumentParser()
|
||||
|
||||
class Entrypoint:
|
||||
def __init__(self, args, parser, connapp):
|
||||
pass
|
||||
""")
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
subparsers = parser.add_subparsers()
|
||||
subparsers.add_parser("existcmd") # Already taken
|
||||
|
||||
plugins = Plugins()
|
||||
plugins._import_plugins_to_argparse(str(plugin_dir), subparsers)
|
||||
|
||||
assert "existcmd" not in plugins.plugins
|
||||
|
||||
def test_preload_registration(self, tmp_path):
|
||||
"""Preload class gets registered in preloads dict."""
|
||||
import argparse
|
||||
|
||||
plugin_dir = tmp_path / "plugins"
|
||||
plugin_dir.mkdir()
|
||||
_write_plugin(plugin_dir / "preloader.py", """\
|
||||
class Preload:
|
||||
def __init__(self, connapp):
|
||||
pass
|
||||
""")
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
subparsers = parser.add_subparsers()
|
||||
|
||||
plugins = Plugins()
|
||||
plugins._import_plugins_to_argparse(str(plugin_dir), subparsers)
|
||||
|
||||
assert "preloader" in plugins.preloads
|
||||
|
||||
def test_invalid_plugin_skipped(self, tmp_path, capsys):
|
||||
"""Invalid plugin is skipped with error message."""
|
||||
import argparse
|
||||
|
||||
plugin_dir = tmp_path / "plugins"
|
||||
plugin_dir.mkdir()
|
||||
_write_plugin(plugin_dir / "badplugin.py", """\
|
||||
MY_GLOBAL = "bad"
|
||||
""")
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
subparsers = parser.add_subparsers()
|
||||
|
||||
plugins = Plugins()
|
||||
plugins._import_plugins_to_argparse(str(plugin_dir), subparsers)
|
||||
|
||||
assert "badplugin" not in plugins.plugins
|
||||
captured = capsys.readouterr()
|
||||
assert "Failed to load plugin" in captured.err or "Failed to load plugin" in captured.out
|
||||
|
||||
def test_empty_directory(self, tmp_path):
|
||||
"""Empty directory doesn't cause errors."""
|
||||
import argparse
|
||||
|
||||
plugin_dir = tmp_path / "plugins"
|
||||
plugin_dir.mkdir()
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
subparsers = parser.add_subparsers()
|
||||
|
||||
plugins = Plugins()
|
||||
plugins._import_plugins_to_argparse(str(plugin_dir), subparsers)
|
||||
|
||||
assert len(plugins.plugins) == 0</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="connpy.tests.test_plugins.TestPluginLoading.test_empty_directory"><code class="name flex">
|
||||
<span>def <span class="ident">test_empty_directory</span></span>(<span>self, tmp_path)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_empty_directory(self, tmp_path):
|
||||
"""Empty directory doesn't cause errors."""
|
||||
import argparse
|
||||
|
||||
plugin_dir = tmp_path / "plugins"
|
||||
plugin_dir.mkdir()
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
subparsers = parser.add_subparsers()
|
||||
|
||||
plugins = Plugins()
|
||||
plugins._import_plugins_to_argparse(str(plugin_dir), subparsers)
|
||||
|
||||
assert len(plugins.plugins) == 0</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Empty directory doesn't cause errors.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_plugins.TestPluginLoading.test_import_from_path"><code class="name flex">
|
||||
<span>def <span class="ident">test_import_from_path</span></span>(<span>self, tmp_path)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_import_from_path(self, tmp_path):
|
||||
p = tmp_path / "mymod.py"
|
||||
_write_plugin(p, """\
|
||||
MY_VAR = 42
|
||||
""")
|
||||
plugins = Plugins()
|
||||
module = plugins._import_from_path(str(p))
|
||||
assert module.MY_VAR == 42</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_plugins.TestPluginLoading.test_import_plugins_to_argparse"><code class="name flex">
|
||||
<span>def <span class="ident">test_import_plugins_to_argparse</span></span>(<span>self, tmp_path)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_import_plugins_to_argparse(self, tmp_path):
|
||||
"""Valid plugins get loaded into argparse."""
|
||||
import argparse
|
||||
|
||||
plugin_dir = tmp_path / "plugins"
|
||||
plugin_dir.mkdir()
|
||||
_write_plugin(plugin_dir / "myplugin.py", """\
|
||||
import argparse
|
||||
|
||||
class Parser:
|
||||
def __init__(self):
|
||||
self.parser = argparse.ArgumentParser(description="My plugin")
|
||||
|
||||
class Entrypoint:
|
||||
def __init__(self, args, parser, connapp):
|
||||
pass
|
||||
""")
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
subparsers = parser.add_subparsers()
|
||||
|
||||
plugins = Plugins()
|
||||
plugins._import_plugins_to_argparse(str(plugin_dir), subparsers)
|
||||
|
||||
assert "myplugin" in plugins.plugins
|
||||
assert "myplugin" in plugins.plugin_parsers</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Valid plugins get loaded into argparse.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_plugins.TestPluginLoading.test_invalid_plugin_skipped"><code class="name flex">
|
||||
<span>def <span class="ident">test_invalid_plugin_skipped</span></span>(<span>self, tmp_path, capsys)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_invalid_plugin_skipped(self, tmp_path, capsys):
|
||||
"""Invalid plugin is skipped with error message."""
|
||||
import argparse
|
||||
|
||||
plugin_dir = tmp_path / "plugins"
|
||||
plugin_dir.mkdir()
|
||||
_write_plugin(plugin_dir / "badplugin.py", """\
|
||||
MY_GLOBAL = "bad"
|
||||
""")
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
subparsers = parser.add_subparsers()
|
||||
|
||||
plugins = Plugins()
|
||||
plugins._import_plugins_to_argparse(str(plugin_dir), subparsers)
|
||||
|
||||
assert "badplugin" not in plugins.plugins
|
||||
captured = capsys.readouterr()
|
||||
assert "Failed to load plugin" in captured.err or "Failed to load plugin" in captured.out</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Invalid plugin is skipped with error message.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_plugins.TestPluginLoading.test_plugin_name_collision"><code class="name flex">
|
||||
<span>def <span class="ident">test_plugin_name_collision</span></span>(<span>self, tmp_path)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_plugin_name_collision(self, tmp_path):
|
||||
"""Plugin with same name as existing subcommand is skipped."""
|
||||
import argparse
|
||||
|
||||
plugin_dir = tmp_path / "plugins"
|
||||
plugin_dir.mkdir()
|
||||
_write_plugin(plugin_dir / "existcmd.py", """\
|
||||
import argparse
|
||||
|
||||
class Parser:
|
||||
def __init__(self):
|
||||
self.parser = argparse.ArgumentParser()
|
||||
|
||||
class Entrypoint:
|
||||
def __init__(self, args, parser, connapp):
|
||||
pass
|
||||
""")
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
subparsers = parser.add_subparsers()
|
||||
subparsers.add_parser("existcmd") # Already taken
|
||||
|
||||
plugins = Plugins()
|
||||
plugins._import_plugins_to_argparse(str(plugin_dir), subparsers)
|
||||
|
||||
assert "existcmd" not in plugins.plugins</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Plugin with same name as existing subcommand is skipped.</p></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_plugins.TestPluginLoading.test_preload_registration"><code class="name flex">
|
||||
<span>def <span class="ident">test_preload_registration</span></span>(<span>self, tmp_path)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_preload_registration(self, tmp_path):
|
||||
"""Preload class gets registered in preloads dict."""
|
||||
import argparse
|
||||
|
||||
plugin_dir = tmp_path / "plugins"
|
||||
plugin_dir.mkdir()
|
||||
_write_plugin(plugin_dir / "preloader.py", """\
|
||||
class Preload:
|
||||
def __init__(self, connapp):
|
||||
pass
|
||||
""")
|
||||
|
||||
parser = argparse.ArgumentParser()
|
||||
subparsers = parser.add_subparsers()
|
||||
|
||||
plugins = Plugins()
|
||||
plugins._import_plugins_to_argparse(str(plugin_dir), subparsers)
|
||||
|
||||
assert "preloader" in plugins.preloads</code></pre>
|
||||
</details>
|
||||
<div class="desc"><p>Preload class gets registered in preloads dict.</p></div>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_plugins.TestVerifyScript"><code class="flex name class">
|
||||
<span>class <span class="ident">TestVerifyScript</span></span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class TestVerifyScript:
|
||||
def test_valid_parser_entrypoint(self, tmp_path):
|
||||
p = tmp_path / "good.py"
|
||||
_write_plugin(p, """\
|
||||
import argparse
|
||||
|
||||
class Parser:
|
||||
def __init__(self):
|
||||
self.parser = argparse.ArgumentParser()
|
||||
|
||||
class Entrypoint:
|
||||
def __init__(self, args, parser, connapp):
|
||||
pass
|
||||
""")
|
||||
plugins = Plugins()
|
||||
assert plugins.verify_script(str(p)) == False
|
||||
|
||||
def test_valid_preload_only(self, tmp_path):
|
||||
p = tmp_path / "preload.py"
|
||||
_write_plugin(p, """\
|
||||
class Preload:
|
||||
def __init__(self, connapp):
|
||||
pass
|
||||
""")
|
||||
plugins = Plugins()
|
||||
assert plugins.verify_script(str(p)) == False
|
||||
|
||||
def test_valid_all_three(self, tmp_path):
|
||||
p = tmp_path / "all.py"
|
||||
_write_plugin(p, """\
|
||||
import argparse
|
||||
|
||||
class Parser:
|
||||
def __init__(self):
|
||||
self.parser = argparse.ArgumentParser()
|
||||
|
||||
class Entrypoint:
|
||||
def __init__(self, args, parser, connapp):
|
||||
pass
|
||||
|
||||
class Preload:
|
||||
def __init__(self, connapp):
|
||||
pass
|
||||
""")
|
||||
plugins = Plugins()
|
||||
assert plugins.verify_script(str(p)) == False
|
||||
|
||||
def test_parser_without_entrypoint(self, tmp_path):
|
||||
p = tmp_path / "bad.py"
|
||||
_write_plugin(p, """\
|
||||
import argparse
|
||||
|
||||
class Parser:
|
||||
def __init__(self):
|
||||
self.parser = argparse.ArgumentParser()
|
||||
""")
|
||||
plugins = Plugins()
|
||||
result = plugins.verify_script(str(p))
|
||||
assert result # Should be a truthy error string
|
||||
assert "Entrypoint" in result
|
||||
|
||||
def test_entrypoint_without_parser(self, tmp_path):
|
||||
p = tmp_path / "bad.py"
|
||||
_write_plugin(p, """\
|
||||
class Entrypoint:
|
||||
def __init__(self, args, parser, connapp):
|
||||
pass
|
||||
""")
|
||||
plugins = Plugins()
|
||||
result = plugins.verify_script(str(p))
|
||||
assert result
|
||||
assert "Parser" in result
|
||||
|
||||
def test_no_valid_class(self, tmp_path):
|
||||
p = tmp_path / "empty.py"
|
||||
_write_plugin(p, """\
|
||||
def some_function():
|
||||
pass
|
||||
""")
|
||||
plugins = Plugins()
|
||||
result = plugins.verify_script(str(p))
|
||||
assert result
|
||||
assert "No valid class" in result
|
||||
|
||||
def test_parser_missing_self_parser(self, tmp_path):
|
||||
p = tmp_path / "bad.py"
|
||||
_write_plugin(p, """\
|
||||
class Parser:
|
||||
def __init__(self):
|
||||
self.something = "not parser"
|
||||
|
||||
class Entrypoint:
|
||||
def __init__(self, args, parser, connapp):
|
||||
pass
|
||||
""")
|
||||
plugins = Plugins()
|
||||
result = plugins.verify_script(str(p))
|
||||
assert result
|
||||
assert "self.parser" in result
|
||||
|
||||
def test_entrypoint_wrong_args(self, tmp_path):
|
||||
p = tmp_path / "bad.py"
|
||||
_write_plugin(p, """\
|
||||
import argparse
|
||||
|
||||
class Parser:
|
||||
def __init__(self):
|
||||
self.parser = argparse.ArgumentParser()
|
||||
|
||||
class Entrypoint:
|
||||
def __init__(self, args):
|
||||
pass
|
||||
""")
|
||||
plugins = Plugins()
|
||||
result = plugins.verify_script(str(p))
|
||||
assert result
|
||||
assert "Entrypoint" in result
|
||||
|
||||
def test_preload_wrong_args(self, tmp_path):
|
||||
p = tmp_path / "bad.py"
|
||||
_write_plugin(p, """\
|
||||
class Preload:
|
||||
def __init__(self, connapp, extra):
|
||||
pass
|
||||
""")
|
||||
plugins = Plugins()
|
||||
result = plugins.verify_script(str(p))
|
||||
assert result
|
||||
assert "Preload" in result
|
||||
|
||||
def test_disallowed_top_level(self, tmp_path):
|
||||
p = tmp_path / "bad.py"
|
||||
_write_plugin(p, """\
|
||||
MY_GLOBAL = "not allowed"
|
||||
|
||||
class Preload:
|
||||
def __init__(self, connapp):
|
||||
pass
|
||||
""")
|
||||
plugins = Plugins()
|
||||
result = plugins.verify_script(str(p))
|
||||
assert result
|
||||
assert "not allowed" in result.lower() or "Plugin can only have" in result
|
||||
|
||||
def test_syntax_error(self, tmp_path):
|
||||
p = tmp_path / "bad.py"
|
||||
_write_plugin(p, """\
|
||||
def broken(
|
||||
""")
|
||||
plugins = Plugins()
|
||||
result = plugins.verify_script(str(p))
|
||||
assert result
|
||||
assert "Syntax error" in result
|
||||
|
||||
def test_if_name_main_allowed(self, tmp_path):
|
||||
p = tmp_path / "good.py"
|
||||
_write_plugin(p, """\
|
||||
class Preload:
|
||||
def __init__(self, connapp):
|
||||
pass
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("standalone")
|
||||
""")
|
||||
plugins = Plugins()
|
||||
assert plugins.verify_script(str(p)) == False
|
||||
|
||||
def test_other_if_not_allowed(self, tmp_path):
|
||||
p = tmp_path / "bad.py"
|
||||
_write_plugin(p, """\
|
||||
import sys
|
||||
|
||||
if sys.platform == "linux":
|
||||
pass
|
||||
|
||||
class Preload:
|
||||
def __init__(self, connapp):
|
||||
pass
|
||||
""")
|
||||
plugins = Plugins()
|
||||
result = plugins.verify_script(str(p))
|
||||
assert result
|
||||
assert "__name__" in result</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="connpy.tests.test_plugins.TestVerifyScript.test_disallowed_top_level"><code class="name flex">
|
||||
<span>def <span class="ident">test_disallowed_top_level</span></span>(<span>self, tmp_path)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_disallowed_top_level(self, tmp_path):
|
||||
p = tmp_path / "bad.py"
|
||||
_write_plugin(p, """\
|
||||
MY_GLOBAL = "not allowed"
|
||||
|
||||
class Preload:
|
||||
def __init__(self, connapp):
|
||||
pass
|
||||
""")
|
||||
plugins = Plugins()
|
||||
result = plugins.verify_script(str(p))
|
||||
assert result
|
||||
assert "not allowed" in result.lower() or "Plugin can only have" in result</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_plugins.TestVerifyScript.test_entrypoint_without_parser"><code class="name flex">
|
||||
<span>def <span class="ident">test_entrypoint_without_parser</span></span>(<span>self, tmp_path)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_entrypoint_without_parser(self, tmp_path):
|
||||
p = tmp_path / "bad.py"
|
||||
_write_plugin(p, """\
|
||||
class Entrypoint:
|
||||
def __init__(self, args, parser, connapp):
|
||||
pass
|
||||
""")
|
||||
plugins = Plugins()
|
||||
result = plugins.verify_script(str(p))
|
||||
assert result
|
||||
assert "Parser" in result</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_plugins.TestVerifyScript.test_entrypoint_wrong_args"><code class="name flex">
|
||||
<span>def <span class="ident">test_entrypoint_wrong_args</span></span>(<span>self, tmp_path)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_entrypoint_wrong_args(self, tmp_path):
|
||||
p = tmp_path / "bad.py"
|
||||
_write_plugin(p, """\
|
||||
import argparse
|
||||
|
||||
class Parser:
|
||||
def __init__(self):
|
||||
self.parser = argparse.ArgumentParser()
|
||||
|
||||
class Entrypoint:
|
||||
def __init__(self, args):
|
||||
pass
|
||||
""")
|
||||
plugins = Plugins()
|
||||
result = plugins.verify_script(str(p))
|
||||
assert result
|
||||
assert "Entrypoint" in result</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_plugins.TestVerifyScript.test_if_name_main_allowed"><code class="name flex">
|
||||
<span>def <span class="ident">test_if_name_main_allowed</span></span>(<span>self, tmp_path)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_if_name_main_allowed(self, tmp_path):
|
||||
p = tmp_path / "good.py"
|
||||
_write_plugin(p, """\
|
||||
class Preload:
|
||||
def __init__(self, connapp):
|
||||
pass
|
||||
|
||||
if __name__ == "__main__":
|
||||
print("standalone")
|
||||
""")
|
||||
plugins = Plugins()
|
||||
assert plugins.verify_script(str(p)) == False</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_plugins.TestVerifyScript.test_no_valid_class"><code class="name flex">
|
||||
<span>def <span class="ident">test_no_valid_class</span></span>(<span>self, tmp_path)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_no_valid_class(self, tmp_path):
|
||||
p = tmp_path / "empty.py"
|
||||
_write_plugin(p, """\
|
||||
def some_function():
|
||||
pass
|
||||
""")
|
||||
plugins = Plugins()
|
||||
result = plugins.verify_script(str(p))
|
||||
assert result
|
||||
assert "No valid class" in result</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_plugins.TestVerifyScript.test_other_if_not_allowed"><code class="name flex">
|
||||
<span>def <span class="ident">test_other_if_not_allowed</span></span>(<span>self, tmp_path)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_other_if_not_allowed(self, tmp_path):
|
||||
p = tmp_path / "bad.py"
|
||||
_write_plugin(p, """\
|
||||
import sys
|
||||
|
||||
if sys.platform == "linux":
|
||||
pass
|
||||
|
||||
class Preload:
|
||||
def __init__(self, connapp):
|
||||
pass
|
||||
""")
|
||||
plugins = Plugins()
|
||||
result = plugins.verify_script(str(p))
|
||||
assert result
|
||||
assert "__name__" in result</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_plugins.TestVerifyScript.test_parser_missing_self_parser"><code class="name flex">
|
||||
<span>def <span class="ident">test_parser_missing_self_parser</span></span>(<span>self, tmp_path)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_parser_missing_self_parser(self, tmp_path):
|
||||
p = tmp_path / "bad.py"
|
||||
_write_plugin(p, """\
|
||||
class Parser:
|
||||
def __init__(self):
|
||||
self.something = "not parser"
|
||||
|
||||
class Entrypoint:
|
||||
def __init__(self, args, parser, connapp):
|
||||
pass
|
||||
""")
|
||||
plugins = Plugins()
|
||||
result = plugins.verify_script(str(p))
|
||||
assert result
|
||||
assert "self.parser" in result</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_plugins.TestVerifyScript.test_parser_without_entrypoint"><code class="name flex">
|
||||
<span>def <span class="ident">test_parser_without_entrypoint</span></span>(<span>self, tmp_path)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_parser_without_entrypoint(self, tmp_path):
|
||||
p = tmp_path / "bad.py"
|
||||
_write_plugin(p, """\
|
||||
import argparse
|
||||
|
||||
class Parser:
|
||||
def __init__(self):
|
||||
self.parser = argparse.ArgumentParser()
|
||||
""")
|
||||
plugins = Plugins()
|
||||
result = plugins.verify_script(str(p))
|
||||
assert result # Should be a truthy error string
|
||||
assert "Entrypoint" in result</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_plugins.TestVerifyScript.test_preload_wrong_args"><code class="name flex">
|
||||
<span>def <span class="ident">test_preload_wrong_args</span></span>(<span>self, tmp_path)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_preload_wrong_args(self, tmp_path):
|
||||
p = tmp_path / "bad.py"
|
||||
_write_plugin(p, """\
|
||||
class Preload:
|
||||
def __init__(self, connapp, extra):
|
||||
pass
|
||||
""")
|
||||
plugins = Plugins()
|
||||
result = plugins.verify_script(str(p))
|
||||
assert result
|
||||
assert "Preload" in result</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_plugins.TestVerifyScript.test_syntax_error"><code class="name flex">
|
||||
<span>def <span class="ident">test_syntax_error</span></span>(<span>self, tmp_path)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_syntax_error(self, tmp_path):
|
||||
p = tmp_path / "bad.py"
|
||||
_write_plugin(p, """\
|
||||
def broken(
|
||||
""")
|
||||
plugins = Plugins()
|
||||
result = plugins.verify_script(str(p))
|
||||
assert result
|
||||
assert "Syntax error" in result</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_plugins.TestVerifyScript.test_valid_all_three"><code class="name flex">
|
||||
<span>def <span class="ident">test_valid_all_three</span></span>(<span>self, tmp_path)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_valid_all_three(self, tmp_path):
|
||||
p = tmp_path / "all.py"
|
||||
_write_plugin(p, """\
|
||||
import argparse
|
||||
|
||||
class Parser:
|
||||
def __init__(self):
|
||||
self.parser = argparse.ArgumentParser()
|
||||
|
||||
class Entrypoint:
|
||||
def __init__(self, args, parser, connapp):
|
||||
pass
|
||||
|
||||
class Preload:
|
||||
def __init__(self, connapp):
|
||||
pass
|
||||
""")
|
||||
plugins = Plugins()
|
||||
assert plugins.verify_script(str(p)) == False</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_plugins.TestVerifyScript.test_valid_parser_entrypoint"><code class="name flex">
|
||||
<span>def <span class="ident">test_valid_parser_entrypoint</span></span>(<span>self, tmp_path)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_valid_parser_entrypoint(self, tmp_path):
|
||||
p = tmp_path / "good.py"
|
||||
_write_plugin(p, """\
|
||||
import argparse
|
||||
|
||||
class Parser:
|
||||
def __init__(self):
|
||||
self.parser = argparse.ArgumentParser()
|
||||
|
||||
class Entrypoint:
|
||||
def __init__(self, args, parser, connapp):
|
||||
pass
|
||||
""")
|
||||
plugins = Plugins()
|
||||
assert plugins.verify_script(str(p)) == False</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_plugins.TestVerifyScript.test_valid_preload_only"><code class="name flex">
|
||||
<span>def <span class="ident">test_valid_preload_only</span></span>(<span>self, tmp_path)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_valid_preload_only(self, tmp_path):
|
||||
p = tmp_path / "preload.py"
|
||||
_write_plugin(p, """\
|
||||
class Preload:
|
||||
def __init__(self, connapp):
|
||||
pass
|
||||
""")
|
||||
plugins = Plugins()
|
||||
assert plugins.verify_script(str(p)) == False</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_plugins.TestPluginLoading" href="#connpy.tests.test_plugins.TestPluginLoading">TestPluginLoading</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="connpy.tests.test_plugins.TestPluginLoading.test_empty_directory" href="#connpy.tests.test_plugins.TestPluginLoading.test_empty_directory">test_empty_directory</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_plugins.TestPluginLoading.test_import_from_path" href="#connpy.tests.test_plugins.TestPluginLoading.test_import_from_path">test_import_from_path</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_plugins.TestPluginLoading.test_import_plugins_to_argparse" href="#connpy.tests.test_plugins.TestPluginLoading.test_import_plugins_to_argparse">test_import_plugins_to_argparse</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_plugins.TestPluginLoading.test_invalid_plugin_skipped" href="#connpy.tests.test_plugins.TestPluginLoading.test_invalid_plugin_skipped">test_invalid_plugin_skipped</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_plugins.TestPluginLoading.test_plugin_name_collision" href="#connpy.tests.test_plugins.TestPluginLoading.test_plugin_name_collision">test_plugin_name_collision</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_plugins.TestPluginLoading.test_preload_registration" href="#connpy.tests.test_plugins.TestPluginLoading.test_preload_registration">test_preload_registration</a></code></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<h4><code><a title="connpy.tests.test_plugins.TestVerifyScript" href="#connpy.tests.test_plugins.TestVerifyScript">TestVerifyScript</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="connpy.tests.test_plugins.TestVerifyScript.test_disallowed_top_level" href="#connpy.tests.test_plugins.TestVerifyScript.test_disallowed_top_level">test_disallowed_top_level</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_plugins.TestVerifyScript.test_entrypoint_without_parser" href="#connpy.tests.test_plugins.TestVerifyScript.test_entrypoint_without_parser">test_entrypoint_without_parser</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_plugins.TestVerifyScript.test_entrypoint_wrong_args" href="#connpy.tests.test_plugins.TestVerifyScript.test_entrypoint_wrong_args">test_entrypoint_wrong_args</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_plugins.TestVerifyScript.test_if_name_main_allowed" href="#connpy.tests.test_plugins.TestVerifyScript.test_if_name_main_allowed">test_if_name_main_allowed</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_plugins.TestVerifyScript.test_no_valid_class" href="#connpy.tests.test_plugins.TestVerifyScript.test_no_valid_class">test_no_valid_class</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_plugins.TestVerifyScript.test_other_if_not_allowed" href="#connpy.tests.test_plugins.TestVerifyScript.test_other_if_not_allowed">test_other_if_not_allowed</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_plugins.TestVerifyScript.test_parser_missing_self_parser" href="#connpy.tests.test_plugins.TestVerifyScript.test_parser_missing_self_parser">test_parser_missing_self_parser</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_plugins.TestVerifyScript.test_parser_without_entrypoint" href="#connpy.tests.test_plugins.TestVerifyScript.test_parser_without_entrypoint">test_parser_without_entrypoint</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_plugins.TestVerifyScript.test_preload_wrong_args" href="#connpy.tests.test_plugins.TestVerifyScript.test_preload_wrong_args">test_preload_wrong_args</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_plugins.TestVerifyScript.test_syntax_error" href="#connpy.tests.test_plugins.TestVerifyScript.test_syntax_error">test_syntax_error</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_plugins.TestVerifyScript.test_valid_all_three" href="#connpy.tests.test_plugins.TestVerifyScript.test_valid_all_three">test_valid_all_three</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_plugins.TestVerifyScript.test_valid_parser_entrypoint" href="#connpy.tests.test_plugins.TestVerifyScript.test_valid_parser_entrypoint">test_valid_parser_entrypoint</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_plugins.TestVerifyScript.test_valid_preload_only" href="#connpy.tests.test_plugins.TestVerifyScript.test_valid_preload_only">test_valid_preload_only</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,269 @@
|
||||
<!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 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>
|
||||
<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</code></h1>
|
||||
</header>
|
||||
<section id="section-intro">
|
||||
<p>Tests for connpy.printer module.</p>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
</section>
|
||||
<section>
|
||||
<h2 class="section-title" id="header-classes">Classes</h2>
|
||||
<dl>
|
||||
<dt id="connpy.tests.test_printer.TestPrinter"><code class="flex name class">
|
||||
<span>class <span class="ident">TestPrinter</span></span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">class TestPrinter:
|
||||
def test_info_output(self, capsys):
|
||||
printer.info("hello world")
|
||||
captured = capsys.readouterr()
|
||||
assert "[i] hello world" in captured.out
|
||||
|
||||
def test_success_output(self, capsys):
|
||||
printer.success("done")
|
||||
captured = capsys.readouterr()
|
||||
assert "[✓] done" in captured.out
|
||||
|
||||
def test_warning_output(self, capsys):
|
||||
printer.warning("careful")
|
||||
captured = capsys.readouterr()
|
||||
assert "[!] careful" in captured.out
|
||||
|
||||
def test_error_output(self, capsys):
|
||||
printer.error("failed")
|
||||
captured = capsys.readouterr()
|
||||
assert "[✗] failed" in captured.err
|
||||
|
||||
def test_debug_output(self, capsys):
|
||||
printer.debug("debug info")
|
||||
captured = capsys.readouterr()
|
||||
assert "[d] debug info" in captured.out
|
||||
|
||||
def test_start_output(self, capsys):
|
||||
printer.start("starting")
|
||||
captured = capsys.readouterr()
|
||||
assert "[+] starting" in captured.out
|
||||
|
||||
def test_custom_output(self, capsys):
|
||||
printer.custom("TAG", "custom message")
|
||||
captured = capsys.readouterr()
|
||||
assert "[TAG] custom message" in captured.out
|
||||
|
||||
def test_multiline_indentation(self, capsys):
|
||||
printer.info("line1\nline2\nline3")
|
||||
captured = capsys.readouterr()
|
||||
lines = captured.out.strip().split("\n")
|
||||
assert lines[0] == "[i] line1"
|
||||
# Second line should be indented by len("[i] ") = 4 chars
|
||||
assert lines[1].startswith(" line2")
|
||||
assert lines[2].startswith(" line3")</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
<h3>Methods</h3>
|
||||
<dl>
|
||||
<dt id="connpy.tests.test_printer.TestPrinter.test_custom_output"><code class="name flex">
|
||||
<span>def <span class="ident">test_custom_output</span></span>(<span>self, capsys)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_custom_output(self, capsys):
|
||||
printer.custom("TAG", "custom message")
|
||||
captured = capsys.readouterr()
|
||||
assert "[TAG] custom message" in captured.out</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_printer.TestPrinter.test_debug_output"><code class="name flex">
|
||||
<span>def <span class="ident">test_debug_output</span></span>(<span>self, capsys)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_debug_output(self, capsys):
|
||||
printer.debug("debug info")
|
||||
captured = capsys.readouterr()
|
||||
assert "[d] debug info" in captured.out</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_printer.TestPrinter.test_error_output"><code class="name flex">
|
||||
<span>def <span class="ident">test_error_output</span></span>(<span>self, capsys)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_error_output(self, capsys):
|
||||
printer.error("failed")
|
||||
captured = capsys.readouterr()
|
||||
assert "[✗] failed" in captured.err</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_printer.TestPrinter.test_info_output"><code class="name flex">
|
||||
<span>def <span class="ident">test_info_output</span></span>(<span>self, capsys)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_info_output(self, capsys):
|
||||
printer.info("hello world")
|
||||
captured = capsys.readouterr()
|
||||
assert "[i] hello world" in captured.out</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_printer.TestPrinter.test_multiline_indentation"><code class="name flex">
|
||||
<span>def <span class="ident">test_multiline_indentation</span></span>(<span>self, capsys)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_multiline_indentation(self, capsys):
|
||||
printer.info("line1\nline2\nline3")
|
||||
captured = capsys.readouterr()
|
||||
lines = captured.out.strip().split("\n")
|
||||
assert lines[0] == "[i] line1"
|
||||
# Second line should be indented by len("[i] ") = 4 chars
|
||||
assert lines[1].startswith(" line2")
|
||||
assert lines[2].startswith(" line3")</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_printer.TestPrinter.test_start_output"><code class="name flex">
|
||||
<span>def <span class="ident">test_start_output</span></span>(<span>self, capsys)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_start_output(self, capsys):
|
||||
printer.start("starting")
|
||||
captured = capsys.readouterr()
|
||||
assert "[+] starting" in captured.out</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_printer.TestPrinter.test_success_output"><code class="name flex">
|
||||
<span>def <span class="ident">test_success_output</span></span>(<span>self, capsys)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_success_output(self, capsys):
|
||||
printer.success("done")
|
||||
captured = capsys.readouterr()
|
||||
assert "[✓] done" in captured.out</code></pre>
|
||||
</details>
|
||||
<div class="desc"></div>
|
||||
</dd>
|
||||
<dt id="connpy.tests.test_printer.TestPrinter.test_warning_output"><code class="name flex">
|
||||
<span>def <span class="ident">test_warning_output</span></span>(<span>self, capsys)</span>
|
||||
</code></dt>
|
||||
<dd>
|
||||
<details class="source">
|
||||
<summary>
|
||||
<span>Expand source code</span>
|
||||
</summary>
|
||||
<pre><code class="python">def test_warning_output(self, capsys):
|
||||
printer.warning("careful")
|
||||
captured = capsys.readouterr()
|
||||
assert "[!] careful" in captured.out</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_printer.TestPrinter" href="#connpy.tests.test_printer.TestPrinter">TestPrinter</a></code></h4>
|
||||
<ul class="">
|
||||
<li><code><a title="connpy.tests.test_printer.TestPrinter.test_custom_output" href="#connpy.tests.test_printer.TestPrinter.test_custom_output">test_custom_output</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_printer.TestPrinter.test_debug_output" href="#connpy.tests.test_printer.TestPrinter.test_debug_output">test_debug_output</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_printer.TestPrinter.test_error_output" href="#connpy.tests.test_printer.TestPrinter.test_error_output">test_error_output</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_printer.TestPrinter.test_info_output" href="#connpy.tests.test_printer.TestPrinter.test_info_output">test_info_output</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_printer.TestPrinter.test_multiline_indentation" href="#connpy.tests.test_printer.TestPrinter.test_multiline_indentation">test_multiline_indentation</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_printer.TestPrinter.test_start_output" href="#connpy.tests.test_printer.TestPrinter.test_start_output">test_start_output</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_printer.TestPrinter.test_success_output" href="#connpy.tests.test_printer.TestPrinter.test_success_output">test_success_output</a></code></li>
|
||||
<li><code><a title="connpy.tests.test_printer.TestPrinter.test_warning_output" href="#connpy.tests.test_printer.TestPrinter.test_warning_output">test_warning_output</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>
|
||||
Reference in New Issue
Block a user