oldap-tools 0.1.4__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
File without changes
@@ -0,0 +1,4 @@
1
+ from .cli import main
2
+
3
+ if __name__ == "__main__":
4
+ main()
oldap_tools/cli.py ADDED
@@ -0,0 +1,114 @@
1
+ from pathlib import Path
2
+
3
+ import typer
4
+ from importlib.metadata import version
5
+
6
+ from oldap_tools.dump_list import dump_list
7
+ from oldap_tools.config import AppConfig
8
+ from oldap_tools.dump_project import dump_project
9
+ from oldap_tools.load_list import load_list
10
+ from oldap_tools.load_project import load_project
11
+
12
+ from oldap_tools.logging import setup_logging
13
+
14
+ app = typer.Typer(
15
+ no_args_is_help=True,
16
+ help="OLDAP command line tools"
17
+ )
18
+
19
+ @app.callback()
20
+ def app_callback(ctx: typer.Context,
21
+ verbose: bool = typer.Option(False, "--verbose", "-v", help="Enable verbose (debug) logging"),
22
+ graphdb_base: str = typer.Option("http://localhost:7200", "--graphdb", "-g", help="GraphDB base URL"),
23
+ repo: str = typer.Option("oldap", "--repo", "-r", help="GraphDB repository"),
24
+ user: str = typer.Option(..., "--user", "-u", help="OLDAP user"),
25
+ password: str = typer.Option(..., "--password", "-p", help="OLDAP password", hide_input=True),
26
+ graphdb_user: str = typer.Option(None, "--graphdb_user", envvar="GRAPHDB_USER", help="GraphDB user"),
27
+ graphdb_password: str = typer.Option(None, "--graphdb_password", envvar="GRAPHDB_PASSWORD", help="GraphDB password", hide_input=True)
28
+ ):
29
+ setup_logging(verbose)
30
+ ctx.obj = AppConfig(
31
+ graphdb_base=graphdb_base,
32
+ repo=repo,
33
+ user=user,
34
+ password=password,
35
+ graphdb_user=graphdb_user,
36
+ graphdb_password=graphdb_password
37
+ )
38
+
39
+ @app.command()
40
+ def show_version():
41
+ """Show version information."""
42
+ typer.echo(version("oldap-tools"))
43
+
44
+ project = typer.Typer(help="Project-related commands")
45
+ app.add_typer(project, name="project")
46
+
47
+ @project.command("dump")
48
+ def project_dump(
49
+ ctx: typer.Context,
50
+ project_id: str = typer.Argument(..., help="Project ID (e.g. swissbritnet, hyha, ...)"),
51
+ out: Path = typer.Option(Path("<project>.trig.gz"), "--out", "-o", help="Output dump file"),
52
+ include_data: bool = typer.Option(True, "--data/--no-data", help="Include '<project>:data' graph"),
53
+ ):
54
+ """Export project data."""
55
+ if out == Path("<project>.trig.gz"):
56
+ out = Path(project_id).with_suffix(".trig.gz")
57
+ typer.echo(f"Exporting '{project_id}' data to {out}")
58
+ cfg = ctx.obj
59
+ dump_project(project_id=project_id,
60
+ graphdb_base=cfg.graphdb_base,
61
+ repo=cfg.repo,
62
+ out=out,
63
+ include_data=include_data,
64
+ user=cfg.user,
65
+ password=cfg.password,
66
+ graphdb_user=cfg.graphdb_user,
67
+ graphdb_password=cfg.graphdb_password)
68
+
69
+ @project.command("load")
70
+ def project_load(ctx: typer.Context,
71
+ inf: Path = typer.Option(Path("dump.trig.gz"), "--inf", "-i", help="Input file for load")):
72
+ cfg = ctx.obj
73
+ load_project(graphdb_base=cfg.graphdb_base,
74
+ repo=cfg.repo,
75
+ inf=inf,
76
+ user=cfg.user,
77
+ password=cfg.password,
78
+ graphdb_user=cfg.graphdb_user,
79
+ graphdb_password=cfg.graphdb_password)
80
+
81
+ lists = typer.Typer(help="List-related commands")
82
+ app.add_typer(lists, name="lists")
83
+
84
+ @lists.command("dump", help="Dump all list data to a YAML file.")
85
+ def list_dump(ctx: typer.Context,
86
+ project_id: str = typer.Argument(..., help="Project ID (e.g. swissbritnet, hyha, ...)"),
87
+ list_id: str = typer.Argument(..., help="List ID (e.g. 'CreativeCommons', 'BuildingCategories', ...)"),
88
+ out: Path = typer.Option(Path("dump.trig"), "--out", "-o", help="Output dump file")):
89
+ cfg = ctx.obj
90
+ dump_list(project_id=project_id,
91
+ list_id=list_id,
92
+ graphdb_base=cfg.graphdb_base,
93
+ repo=cfg.repo,
94
+ filepath=out,
95
+ user=cfg.user,
96
+ password=cfg.password,
97
+ graphdb_user = cfg.graphdb_user,
98
+ graphdb_password = cfg.graphdb_password
99
+ )
100
+
101
+ @lists.command("load", help="Load project data from a JSON/YAML file.")
102
+ def list_load(ctx: typer.Context,
103
+ project_id: str = typer.Argument(..., help="Project ID (e.g. swissbritnet, hyha, ...)"),
104
+ inf: Path = typer.Option(Path("dump.trig.gz"), "--inf", "-i", help="Input file for load")):
105
+ cfg = ctx.obj
106
+ load_list(project_id=project_id,
107
+ graphdb_base=cfg.graphdb_base,
108
+ repo=cfg.repo,
109
+ filepath=inf,
110
+ user=cfg.user,
111
+ password=cfg.password)
112
+
113
+ def main():
114
+ app()
oldap_tools/config.py ADDED
@@ -0,0 +1,11 @@
1
+ # src/oldap_tools/config.py
2
+ from dataclasses import dataclass
3
+
4
+ @dataclass(frozen=True)
5
+ class AppConfig:
6
+ graphdb_base: str
7
+ repo: str
8
+ user: str | None = None
9
+ password: str | None = None
10
+ graphdb_user: str | None = None
11
+ graphdb_password: str | None = None
@@ -0,0 +1,43 @@
1
+ import logging
2
+ from pathlib import Path
3
+
4
+ import typer
5
+ from oldaplib.src.connection import Connection
6
+ from oldaplib.src.helpers.oldaperror import OldapError
7
+ from oldaplib.src.oldaplist_helpers import ListFormat, dump_list_to
8
+ from oldaplib.src.project import Project
9
+
10
+ log = logging.getLogger(__name__)
11
+
12
+ def dump_list(project_id: str,
13
+ list_id: str,
14
+ graphdb_base: str,
15
+ repo: str,
16
+ filepath: Path,
17
+ user: str,
18
+ password: str,
19
+ graphdb_user: str | None = None,
20
+ graphdb_password: str | None = None
21
+ ):
22
+ try:
23
+ con = Connection(server=graphdb_base,
24
+ repo=repo,
25
+ dbuser=graphdb_user,
26
+ dbpassword=graphdb_password,
27
+ userId=user,
28
+ credentials=password,
29
+ context_name="DEFAULT")
30
+ yamlfile = dump_list_to(con=con,
31
+ project=project_id,
32
+ oldapListId=list_id,
33
+ listformat=ListFormat.YAML,
34
+ ignore_cache=False)
35
+ except OldapError as error:
36
+ log.error(f"ERROR: Failed to connect to GraphDB database at '{graphdb_base}': {error}")
37
+ raise typer.Exit(code=1)
38
+ except FileNotFoundError as error:
39
+ log.error(f"ERROR: File {filepath} not found': {error}")
40
+ raise typer.Exit(code=1)
41
+
42
+ with open(filepath, "w", encoding="utf-8") as f:
43
+ f.write(yamlfile)
@@ -0,0 +1,127 @@
1
+ import gzip
2
+ import json
3
+ from datetime import datetime
4
+ from pathlib import Path
5
+
6
+ import requests
7
+ import typer
8
+ import logging
9
+
10
+ from oldaplib.src.connection import Connection
11
+ from oldaplib.src.helpers.context import Context
12
+ from oldaplib.src.helpers.oldaperror import OldapError
13
+ from oldaplib.src.helpers.serializer import serializer
14
+ from oldaplib.src.role import Role
15
+ from oldaplib.src.project import Project
16
+ from oldaplib.src.user import User
17
+ from oldaplib.src.xsd.xsd_qname import Xsd_QName
18
+ from rdflib import Dataset
19
+
20
+ log = logging.getLogger(__name__)
21
+
22
+ def export_graphs_as_trig(
23
+ graphdb_base: str, # e.g. "http://localhost:7200"
24
+ repo: str, # e.g. "oldap"
25
+ graph_iris: list[str], # the 4 graphs you want
26
+ auth: tuple[str, str] | None = None,
27
+ timeout: int = 120,
28
+ ) -> str:
29
+ ds = Dataset()
30
+
31
+ for g in graph_iris:
32
+ # RDF4J "statements" endpoint; context must be given as <IRI>
33
+ url = f"{graphdb_base.rstrip('/')}/repositories/{repo}/statements"
34
+ params = {"context": f"<{g}>"}
35
+ r = requests.get(
36
+ url,
37
+ params=params,
38
+ headers={"Accept": "application/n-quads"},
39
+ auth=auth,
40
+ timeout=timeout,
41
+ )
42
+ if r.status_code != 200:
43
+ log.error(f"ERROR: Request to '{url}' failed with status code {r.status_code}")
44
+ raise typer.Exit(code=1)
45
+
46
+ # N-Quads keeps the graph/context in each statement -> perfect for Dataset
47
+ ds.parse(data=r.text, format="nquads")
48
+
49
+ trig = ds.serialize(format="trig")
50
+ return trig.decode("utf-8") if isinstance(trig, bytes) else trig
51
+
52
+
53
+ def dump_project(project_id: str,
54
+ graphdb_base: str,
55
+ repo: str,
56
+ out: Path,
57
+ include_data: bool,
58
+ user: str,
59
+ password: str,
60
+ graphdb_user: str | None = None,
61
+ graphdb_password: str | None = None):
62
+ try:
63
+ con = Connection(server=graphdb_base,
64
+ repo = repo,
65
+ dbuser=graphdb_user,
66
+ dbpassword=graphdb_password,
67
+ userId=user,
68
+ credentials=password)
69
+ except OldapError as e:
70
+ log.error(f"ERROR: Failed to connect to GraphDB database at '{graphdb_base}': {e}")
71
+ raise typer.Exit(code=1)
72
+
73
+ try:
74
+ project = Project.read(con=con, projectIri_SName=project_id)
75
+ except OldapError as e:
76
+ log.error(f"ERROR: Failed to connect to read project '{project_id}': {e}")
77
+ raise typer.Exit(code=1)
78
+
79
+ trig = "################################################################################\n"
80
+ trig += f"# Project: {project.projectShortName}\n"
81
+ trig += f"# Date: {datetime.now().isoformat()}\n"
82
+ trig += "################################################################################\n"
83
+ trig += "\n#\n# User info\n#\n"
84
+ userIris = User.search(con=con, inProject=project.projectIri)
85
+ for userIri in userIris:
86
+ user = User.read(con=con, userId=str(userIri))
87
+ user_json = json.dumps(user, default=serializer.encoder_default)
88
+ trig += "#>> " + user_json + "\n"
89
+ trig += "#<<\n\n"
90
+
91
+ context = Context(name=con.context_name)
92
+ trig += context.turtle_context
93
+ trig += "#\n# Load the oldap:admin part\n#\n"
94
+ trig += "oldap:admin {"
95
+
96
+ trig += "\n#\n# Project info\n#\n"
97
+ trig += project.trig_to_str(created=project.created, modified=project.modified, indent=1)
98
+ trig += " .\n\n"
99
+
100
+ trig += "\n#\n# Roles info\n#\n"
101
+ roleQNames = Role.search(con=con, definedByProject=project.projectIri)
102
+ for roleQName in roleQNames:
103
+ role = Role.read(con=con, qname=roleQName)
104
+ trig += role.trig_to_str(created=role.created, modified=role.modified, indent=1)
105
+ trig += " .\n\n"
106
+
107
+ trig += "\n}\n\n"
108
+
109
+ project_graphs = [
110
+ str(context.qname2iri(Xsd_QName(project.projectShortName, "shacl"))),
111
+ str(context.qname2iri(Xsd_QName(project.projectShortName, "onto"))),
112
+ str(context.qname2iri(Xsd_QName(project.projectShortName, "lists"))),
113
+ ]
114
+ if include_data:
115
+ project_graphs.append(str(context.qname2iri(Xsd_QName(project.projectShortName, "data"))))
116
+
117
+ trig += export_graphs_as_trig(
118
+ graphdb_base="http://localhost:7200",
119
+ repo="oldap",
120
+ graph_iris=project_graphs,
121
+ auth=None, # or None
122
+ )
123
+
124
+ with gzip.open(out, "wt", encoding="utf-8", newline="") as f:
125
+ f.write(trig)
126
+
127
+
@@ -0,0 +1,39 @@
1
+ import logging
2
+ from pathlib import Path
3
+
4
+ import typer
5
+ from oldaplib.src.connection import Connection
6
+ from oldaplib.src.helpers.oldaperror import OldapError
7
+ from oldaplib.src.oldaplist_helpers import load_list_from_yaml
8
+ from oldaplib.src.project import Project
9
+
10
+ log = logging.getLogger(__name__)
11
+
12
+ def load_list(project_id: str,
13
+ graphdb_base: str,
14
+ repo: str,
15
+ filepath: Path,
16
+ user: str,
17
+ password: str,
18
+ graphdb_user: str | None = None,
19
+ graphdb_password: str | None = None):
20
+
21
+ try:
22
+ connection = Connection(server=graphdb_base,
23
+ repo=repo,
24
+ dbuser=graphdb_user,
25
+ dbpassword=graphdb_password,
26
+ userId=user,
27
+ credentials=password,
28
+ context_name="DEFAULT")
29
+ project = Project.read(connection, project_id)
30
+ listnodes = load_list_from_yaml(con=connection,
31
+ project=project_id,
32
+ filepath=filepath)
33
+ except OldapError as error:
34
+ log.error(f"ERROR: Failed to connect to GraphDB database at '{graphdb_base}': {error}")
35
+ raise typer.Exit(code=1)
36
+ except FileNotFoundError as error:
37
+ log.error(f"ERROR: File {filepath} not found': {error}")
38
+ raise typer.Exit(code=1)
39
+
@@ -0,0 +1,110 @@
1
+ import gzip
2
+ import json
3
+ import logging
4
+ from pathlib import Path
5
+
6
+ import requests
7
+ import typer
8
+ from oldaplib.src.cachesingleton import CacheSingletonRedis
9
+ from oldaplib.src.connection import Connection
10
+ from oldaplib.src.helpers.oldaperror import OldapErrorAlreadyExists, OldapError, OldapErrorNotFound
11
+ from oldaplib.src.helpers.serializer import serializer
12
+ from oldaplib.src.user import User
13
+
14
+ log = logging.getLogger(__name__)
15
+
16
+ def import_trig(
17
+ graphdb_base: str,
18
+ repo: str,
19
+ trig_str: str,
20
+ auth: tuple[str, str] | None = None,
21
+ timeout: int = 120,
22
+ ):
23
+ url = f"{graphdb_base.rstrip('/')}/repositories/{repo}/statements"
24
+ r = requests.post(
25
+ url,
26
+ data=trig_str.encode("utf-8"),
27
+ headers={"Content-Type": "application/trig"},
28
+ auth=auth,
29
+ timeout=timeout,
30
+ )
31
+ if r.status_code != 200:
32
+ log.error(f"ERROR: Request to '{url}' failed with status code {r.status_code}")
33
+ raise typer.Exit(code=1)
34
+
35
+
36
+ def import_trig_gz(
37
+ graphdb_base: str,
38
+ repo: str,
39
+ trig_gz: bytes,
40
+ auth: tuple[str, str] | None = None,
41
+ timeout: int = 120,
42
+ ):
43
+ url = f"{graphdb_base.rstrip('/')}/repositories/{repo}/statements"
44
+ r = requests.post(
45
+ url,
46
+ data=trig_gz,
47
+ headers={
48
+ "Content-Type": "application/trig",
49
+ "Content-Encoding": "gzip",
50
+ },
51
+ auth=auth,
52
+ timeout=timeout,
53
+ )
54
+ if r.status_code < 200 or r.status_code >= 300:
55
+ log.error(f"ERROR: Request to '{url}' failed with status code {r.status_code}")
56
+ raise typer.Exit(code=1)
57
+
58
+
59
+ def load_project(graphdb_base: str,
60
+ repo: str,
61
+ inf: Path,
62
+ user: str,
63
+ password: str,
64
+ graphdb_user: str | None = None,
65
+ graphdb_password: str | None = None) -> None:
66
+ cache = CacheSingletonRedis()
67
+ cache.clear()
68
+
69
+ with open(inf, "rb") as f:
70
+ import_trig_gz(graphdb_base=graphdb_base,
71
+ repo=repo,
72
+ auth=(graphdb_user, graphdb_password) if graphdb_user and graphdb_password else None,
73
+ trig_gz=f.read())
74
+
75
+ try:
76
+ con = Connection(server=graphdb_base,
77
+ repo=repo,
78
+ dbuser=graphdb_user,
79
+ dbpassword=graphdb_password,
80
+ userId=user,
81
+ credentials=password)
82
+ except OldapError as e:
83
+ log.error(f"ERROR: Failed to connect to GraphDB database at '{graphdb_base}': {e}")
84
+ raise typer.Exit(code=1)
85
+
86
+ with gzip.open(inf, "rt", encoding="utf-8") as f:
87
+ for line in f:
88
+ if line.startswith('#>>'):
89
+ user_json = line[3:].strip()
90
+ user = json.loads(user_json, object_hook=serializer.make_decoder_hook(connection=con))
91
+ try:
92
+ existing_user = User.read(con=con, userId=user.userId)
93
+ except OldapErrorNotFound:
94
+ # user does not exist -> create it
95
+ user.create(keep_dates=True)
96
+ log.info(f"Created user {user.userId}")
97
+ else:
98
+ # user exists -> update it
99
+ if user.hasRole != existing_user.hasRole or user.inProject != existing_user.inProject:
100
+ existing_user.delete()
101
+ user.create(keep_dates=True)
102
+ log.info(f"Updated (replaced) user {user.userId}")
103
+ pass
104
+ if line.startswith('#<<'):
105
+ break
106
+ cache = CacheSingletonRedis()
107
+ cache.clear()
108
+
109
+
110
+
oldap_tools/logging.py ADDED
@@ -0,0 +1,13 @@
1
+ import logging
2
+ import sys
3
+
4
+ def setup_logging(verbose: bool = False) -> None:
5
+ level = logging.DEBUG if verbose else logging.INFO
6
+
7
+ logging.basicConfig(
8
+ level=level,
9
+ format="%(levelname)s: %(message)s",
10
+ handlers=[
11
+ logging.StreamHandler(sys.stderr)
12
+ ],
13
+ )
@@ -0,0 +1,122 @@
1
+ Metadata-Version: 2.1
2
+ Name: oldap-tools
3
+ Version: 0.1.4
4
+ Summary: CLI tools for OLDAP
5
+ License: GPL-3.0-only
6
+ Author: Lukas Rosenthaler
7
+ Author-email: lukas.rosenthaler@unibas.ch
8
+ Requires-Python: >=3.11,<4.0
9
+ Classifier: License :: OSI Approved :: GNU General Public License v3 (GPLv3)
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Requires-Dist: oldaplib (>=0.4.1,<0.5.0)
14
+ Requires-Dist: rdflib (>=7.5.0,<8.0.0)
15
+ Requires-Dist: typer (>=0.20.0,<0.21.0)
16
+ Description-Content-Type: text/markdown
17
+
18
+ [![PyPI version](https://badge.fury.io/py/oldap-tools.svg)](https://badge.fury.io/py/oldap-tools)
19
+ [![GitHub release](https://img.shields.io/github/v/release/OMAS-IIIF/oldap-tools)](https://github.com/OMAS-IIIF/oldap-tools/releases)
20
+ # OLDAP tools
21
+
22
+ OLDAP tools is a CLI tool for managing parts of the OLDAP framework. It allows to
23
+
24
+ - dump all the data of a given project to a gzipped TriG file
25
+ - load a project from a gzipped TriG file created by oldap-tools
26
+ - load a hierarchical list from a YAML file
27
+ - dump a hierarchical list to a YAML file
28
+
29
+ # Installation
30
+
31
+ The installation is done using pip: `pip install oldap-tools`
32
+
33
+ # Usage
34
+
35
+ The CLI tool provides the following commands:
36
+
37
+ - `oldap-tools project dump`: Dump all the data of a given project to a gzipped TriG file
38
+ - `oldap-tools project load`: Load a project from a gzipped TriG file created by oldap-tools
39
+ - `oldap-tools list dump`: Dump a hierarchical list to a YAML file
40
+ - `oldap-tools list load`: Load a hierarchical list from a YAML file
41
+
42
+ # Common options
43
+
44
+ - `--graphdb`, `-g`: URL of the GraphDB server (default: "http://localhost:7200")
45
+ - `--repo`, `-r`: Name of the repository (default: "oldap")
46
+ - `--user`, `-u`: OLDAP user (*required*) which performs the operations
47
+ - `--password` `-p`: OLDAP password (*required*)
48
+ - `--graphdb_user`: GraphDB user (default: None). Not needed if GraphDB runs without athentification.
49
+ - `--graphdb_password`: GraphDB password (default: None). Not needed if GraphDB runs without athentification.
50
+ - `--verbose`, `-v`: Print more information
51
+
52
+ # Command
53
+
54
+ ## Project dump
55
+
56
+ This command dumps all the data of a given project to a gzipped TriG file. It includes user information
57
+ of all users associated with the project. The command has the following syntax (in addition to the common options):
58
+
59
+ ```oldap-tools [common_options] [graphdb-options] project dump [-out <filename>] [--data | --no-data] [-verbose] <project_id>```
60
+
61
+ The graphdb options see above. The other options are defined as follows:
62
+
63
+ - `-out <filename>`: Name of the output file (default: "<project_id>.trig.gz")
64
+ - `--data | --no-data`: Include or exclude the data of the project (default: include)
65
+ - `-verbose`: Print more information
66
+ - `<project_id>`: Project identifier (project shortname)
67
+
68
+ The file is basically a dump of the project specific named graphs of the GraphDB repository.
69
+ This are the following graphs:
70
+
71
+ - `<project_id>:shacl`: Contains all the SHACL shapes of the project
72
+ - `<project_id>:onto`: Contains all the OWL ontology information of the project
73
+ - `<project_id>:lists`: Contains all the hierarchical lists of the project
74
+ - `<project_id>:data`: Contains all the resources (instances) of the project
75
+
76
+ The user information is stored as special comment in the TriG file and is interpreted by oldap-tools project load.
77
+
78
+ ## Project load
79
+
80
+ This command loads a project from a gzipped TriG file created by oldap-tools. It has the following syntax
81
+ (in addition to the common options):
82
+
83
+ ```oldap-tools [common_options] [graphdb-options] project load --i <filename>```
84
+
85
+ The options are as follows:
86
+
87
+ - `--inf`, `-i`: Name of the input file (required)
88
+ - `-verbose`: Print more information
89
+
90
+ If a user does not exist, then the user is created. If the User is already existing, then the user is replaced.
91
+
92
+ *NOTE: This will change in the future in order to only update project specific permissions to the existing user.*
93
+
94
+ ## List dump
95
+
96
+ This command dumps a hierarchical list to a YAML file. This file can be edited to add/remove or change list items.
97
+ The command has the following syntax (in addition to the common options):
98
+
99
+ ```oldap-tools [common_options] list dump [-out <filename>] <project_id> <list_id>```
100
+
101
+ This command generates a YAML file which can be edited and contains the list and all it nodes
102
+
103
+ The options are as follows:
104
+
105
+ - `-out `, `-o`: Output file
106
+ - `<project_id>`: Project identifier (project shortname)
107
+ - `<list_id>`: List identifier
108
+
109
+ ## List load
110
+
111
+ This command loads a hierarchical list from a YAML file into the given project. The command has the following syntax
112
+ (in addition to the common options):
113
+
114
+ ```oldap-tools [common_options] list load --inf <filename> <project_id>```
115
+
116
+ The options are as follows:
117
+
118
+ - `--inf`, `-i`: Name of the input file (required)
119
+ - `<project_id>`: Project identifier (project shortname)
120
+
121
+
122
+
@@ -0,0 +1,13 @@
1
+ oldap_tools/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ oldap_tools/__main__.py,sha256=0g3iknXOS9gZUcpL_trgAcuCJnZZKjdsT_xt61WOVb4,60
3
+ oldap_tools/cli.py,sha256=R2QR1sJ9eX3TOjkoGOUER31aaTLBVeJfL73md2Bsz-g,4599
4
+ oldap_tools/config.py,sha256=_VrFlBZG5EBeoA5HyCxxMuSM8qRPJWUN0QILOrYjKMU,275
5
+ oldap_tools/dump_list.py,sha256=kHW-u57Pgso0cKl2R59KQLBY9J8abpRIDtX8iS6rRgs,1577
6
+ oldap_tools/dump_project.py,sha256=0GaIVLB0nURiPJVl5_y00y3E6E0XRINFY2qWZnIpSQ0,4535
7
+ oldap_tools/load_list.py,sha256=i4npHMRoZuPXyizAeab5qjzlIyvMEaFGiuJq3P-7xxQ,1472
8
+ oldap_tools/load_project.py,sha256=KLfGHzIXAH2fwtTyzkmC7uozxmCs2geQp-XjBbGQXEo,3661
9
+ oldap_tools/logging.py,sha256=qxBtN_HcUMYeSAHZVQ1YiWd5pgB-beBwEUSOv5f_KvM,305
10
+ oldap_tools-0.1.4.dist-info/METADATA,sha256=zdYmoBWIjikFcH6ABZBidGRTmBaSYUlUjaKREkwf1Is,4891
11
+ oldap_tools-0.1.4.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
12
+ oldap_tools-0.1.4.dist-info/entry_points.txt,sha256=3UTWo7Z79A2m4rmTMnBeQZI5BXT19VJSPIdu7pWMp2I,52
13
+ oldap_tools-0.1.4.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: poetry-core 1.9.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ oldap-tools=oldap_tools.cli:main
3
+