threadlepy 0.1.0__tar.gz → 0.1.2__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. {threadlepy-0.1.0 → threadlepy-0.1.2}/CHANGELOG.md +11 -0
  2. {threadlepy-0.1.0 → threadlepy-0.1.2}/MANIFEST.in +1 -0
  3. threadlepy-0.1.2/PKG-INFO +69 -0
  4. threadlepy-0.1.2/README.md +52 -0
  5. {threadlepy-0.1.0 → threadlepy-0.1.2}/pyproject.toml +3 -3
  6. {threadlepy-0.1.0 → threadlepy-0.1.2}/src/threadlepy/__init__.py +1 -1
  7. {threadlepy-0.1.0 → threadlepy-0.1.2}/src/threadlepy/client.py +7 -0
  8. {threadlepy-0.1.0 → threadlepy-0.1.2}/src/threadlepy/commands.py +120 -34
  9. threadlepy-0.1.2/src/threadlepy/py.typed +1 -0
  10. threadlepy-0.1.2/src/threadlepy.egg-info/PKG-INFO +69 -0
  11. {threadlepy-0.1.0 → threadlepy-0.1.2}/src/threadlepy.egg-info/SOURCES.txt +1 -0
  12. threadlepy-0.1.0/PKG-INFO +0 -278
  13. threadlepy-0.1.0/README.md +0 -261
  14. threadlepy-0.1.0/src/threadlepy.egg-info/PKG-INFO +0 -278
  15. {threadlepy-0.1.0 → threadlepy-0.1.2}/LICENSE +0 -0
  16. {threadlepy-0.1.0 → threadlepy-0.1.2}/docs/threadlepy_tutorial.ipynb +0 -0
  17. {threadlepy-0.1.0 → threadlepy-0.1.2}/scripts/test_commands.py +0 -0
  18. {threadlepy-0.1.0 → threadlepy-0.1.2}/scripts/test_session.py +0 -0
  19. {threadlepy-0.1.0 → threadlepy-0.1.2}/setup.cfg +0 -0
  20. {threadlepy-0.1.0 → threadlepy-0.1.2}/src/threadlepy/Examples/Scripts/create.txt +0 -0
  21. {threadlepy-0.1.0 → threadlepy-0.1.2}/src/threadlepy/Examples/dscw.tsv +0 -0
  22. {threadlepy-0.1.0 → threadlepy-0.1.2}/src/threadlepy/Examples/dscw_nodeset.tsv +0 -0
  23. {threadlepy-0.1.0 → threadlepy-0.1.2}/src/threadlepy/Examples/lazega.tsv +0 -0
  24. {threadlepy-0.1.0 → threadlepy-0.1.2}/src/threadlepy/Examples/lazega_female.tsv +0 -0
  25. {threadlepy-0.1.0 → threadlepy-0.1.2}/src/threadlepy/Examples/lazega_female_nodeset.tsv +0 -0
  26. {threadlepy-0.1.0 → threadlepy-0.1.2}/src/threadlepy/Examples/lazega_nodes.tsv +0 -0
  27. {threadlepy-0.1.0 → threadlepy-0.1.2}/src/threadlepy/Examples/mynet.tsv +0 -0
  28. {threadlepy-0.1.0 → threadlepy-0.1.2}/src/threadlepy/Examples/mynet_nodesetfile.tsv +0 -0
  29. {threadlepy-0.1.0 → threadlepy-0.1.2}/src/threadlepy/Examples/mynodes.tsv +0 -0
  30. {threadlepy-0.1.0 → threadlepy-0.1.2}/src/threadlepy.egg-info/dependency_links.txt +0 -0
  31. {threadlepy-0.1.0 → threadlepy-0.1.2}/src/threadlepy.egg-info/top_level.txt +0 -0
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.2
4
+
5
+ - Added one-line docstrings for public command wrappers.
6
+ - Added `Literal` type hints for finite-choice parameters to improve editor completions.
7
+ - Marked the package as typed with `py.typed`.
8
+
9
+ ## 0.1.1
10
+
11
+ - Updated PyPI project description to match README.
12
+ - Synchronized package metadata version with the 0.1.1 release.
13
+
3
14
  ## 0.1.0
4
15
 
5
16
  - Expanded Python command wrappers to better correspond to Threadle.
@@ -4,6 +4,7 @@ include CHANGELOG.md
4
4
  include pyproject.toml
5
5
 
6
6
  recursive-include src/threadlepy/Examples *.tsv *.txt
7
+ include src/threadlepy/py.typed
7
8
  recursive-include docs *.ipynb
8
9
  recursive-include scripts *.py
9
10
 
@@ -0,0 +1,69 @@
1
+ Metadata-Version: 2.4
2
+ Name: threadlepy
3
+ Version: 0.1.2
4
+ Summary: Python client for the Threadle CLI JSON interface.
5
+ Author: Yukun Jiao
6
+ License-Expression: MIT
7
+ Project-URL: Homepage, https://github.com/YukunJiao/threadlepy
8
+ Project-URL: Issues, https://github.com/YukunJiao/threadlepy/issues
9
+ Project-URL: Documentation, https://github.com/YukunJiao/threadlepy#readme
10
+ Project-URL: Source, https://github.com/YukunJiao/threadlepy
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Operating System :: OS Independent
13
+ Requires-Python: >=3.9
14
+ Description-Content-Type: text/markdown
15
+ License-File: LICENSE
16
+ Dynamic: license-file
17
+
18
+ # threadlepy
19
+
20
+ Python client for the Threadle CLI JSON interface.
21
+
22
+ `threadlepy` starts a Threadle subprocess and exposes Python wrappers for core Threadle workflows.
23
+
24
+ ## Installation
25
+
26
+ ```bash
27
+ pip install threadlepy
28
+ ```
29
+
30
+ Requirements:
31
+
32
+ - Python 3.9+
33
+ - A working `threadle` executable available on `PATH`
34
+
35
+ ## Quick Start
36
+
37
+ ```python
38
+ import threadlepy
39
+ import threadlepy.commands as th
40
+
41
+ with threadlepy.session(timeout=3600):
42
+ examples = th.load_examples("lazega")
43
+ lazega = examples["lazega"]
44
+
45
+ print(th.info(lazega))
46
+
47
+ path = th.shortest_path(
48
+ lazega,
49
+ node1id=1,
50
+ node2id=23,
51
+ layernames="friends",
52
+ )
53
+
54
+ print(path)
55
+ ```
56
+
57
+ If `threadle` is not on `PATH`, pass the executable path explicitly:
58
+
59
+ ```python
60
+ threadlepy.start("/full/path/to/threadle")
61
+ ```
62
+
63
+ ## Documentation
64
+
65
+ For more examples and workflows, see:
66
+
67
+ ```text
68
+ docs/threadlepy_tutorial.ipynb
69
+ ```
@@ -0,0 +1,52 @@
1
+ # threadlepy
2
+
3
+ Python client for the Threadle CLI JSON interface.
4
+
5
+ `threadlepy` starts a Threadle subprocess and exposes Python wrappers for core Threadle workflows.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ pip install threadlepy
11
+ ```
12
+
13
+ Requirements:
14
+
15
+ - Python 3.9+
16
+ - A working `threadle` executable available on `PATH`
17
+
18
+ ## Quick Start
19
+
20
+ ```python
21
+ import threadlepy
22
+ import threadlepy.commands as th
23
+
24
+ with threadlepy.session(timeout=3600):
25
+ examples = th.load_examples("lazega")
26
+ lazega = examples["lazega"]
27
+
28
+ print(th.info(lazega))
29
+
30
+ path = th.shortest_path(
31
+ lazega,
32
+ node1id=1,
33
+ node2id=23,
34
+ layernames="friends",
35
+ )
36
+
37
+ print(path)
38
+ ```
39
+
40
+ If `threadle` is not on `PATH`, pass the executable path explicitly:
41
+
42
+ ```python
43
+ threadlepy.start("/full/path/to/threadle")
44
+ ```
45
+
46
+ ## Documentation
47
+
48
+ For more examples and workflows, see:
49
+
50
+ ```text
51
+ docs/threadlepy_tutorial.ipynb
52
+ ```
@@ -4,8 +4,8 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "threadlepy"
7
- version = "0.1.0"
8
- description = "Python wrapper for the Threadle command-line interface"
7
+ version = "0.1.2"
8
+ description = "Python client for the Threadle CLI JSON interface."
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.9"
11
11
  license = "MIT"
@@ -27,4 +27,4 @@ Source = "https://github.com/YukunJiao/threadlepy"
27
27
  where = ["src"]
28
28
 
29
29
  [tool.setuptools.package-data]
30
- threadlepy = ["Examples/*.tsv", "Examples/Scripts/*.txt"]
30
+ threadlepy = ["py.typed", "Examples/*.tsv", "Examples/Scripts/*.txt"]
@@ -2,7 +2,7 @@
2
2
 
3
3
  from .client import ThreadleStruct, configure, is_available, raw_cmd, session, start, stop
4
4
 
5
- __version__ = "0.1.0"
5
+ __version__ = "0.1.2"
6
6
 
7
7
  __all__ = [
8
8
  "ThreadleStruct",
@@ -48,6 +48,7 @@ def configure(
48
48
  default_timeout = float(timeout)
49
49
 
50
50
  def stop():
51
+ """Stop the running Threadle subprocess, if one is active."""
51
52
  global proc
52
53
  if proc and proc.poll() is None:
53
54
  print("threadle stopped")
@@ -56,6 +57,7 @@ def stop():
56
57
  proc = None
57
58
 
58
59
  def start(path: str | None = None) -> subprocess.Popen[str]:
60
+ """Start the Threadle CLI JSON subprocess and return the process handle."""
59
61
  global proc
60
62
  if path is None or not str(path).strip():
61
63
  exe = shutil.which("threadle")
@@ -112,9 +114,11 @@ def session(path: str | None = None, **config: Any) -> Iterator[subprocess.Popen
112
114
  stop()
113
115
 
114
116
  def collect_args(**kwargs):
117
+ """Return keyword arguments whose values are not ``None``."""
115
118
  return {k: v for k, v in kwargs.items() if v is not None}
116
119
 
117
120
  def json_cmd(command: str, args: Optional[Dict[str, Any]] = None, assign: Optional[str] = None) -> str:
121
+ """Build a JSON command payload for the Threadle CLI."""
118
122
  dto = {
119
123
  "Assign": assign,
120
124
  "Command": str(command),
@@ -123,6 +127,7 @@ def json_cmd(command: str, args: Optional[Dict[str, Any]] = None, assign: Option
123
127
  return json.dumps(dto, ensure_ascii=False)
124
128
 
125
129
  def send_command(cmd_json: str, timeout: Optional[float] = None) -> Dict[str, Any]:
130
+ """Send a JSON command to Threadle and wait for a JSON response."""
126
131
  global proc
127
132
  if proc is None or proc.poll() is not None:
128
133
  raise RuntimeError("Threadle process is not running.")
@@ -177,6 +182,7 @@ def send_command(cmd_json: str, timeout: Optional[float] = None) -> Dict[str, An
177
182
  raise TimeoutError(hint)
178
183
 
179
184
  def unwrap(resp: Dict[str, Any], *, print_message: bool = True) -> Any:
185
+ """Validate a Threadle response and return its payload."""
180
186
  if resp.get("Success") is not True:
181
187
  code = resp.get("Code") or "Error"
182
188
  msg = resp.get("Message") or "Threadle error"
@@ -209,6 +215,7 @@ def call(
209
215
  return_response: bool = False,
210
216
  drop: tuple[str, ...] = (),
211
217
  ) -> Any:
218
+ """Call a typed Threadle command wrapper using the caller's local variables."""
212
219
  args = collect_args(**locals_dict)
213
220
  args.pop("cmd", None)
214
221
  args.pop("assign", None)