smartmodels 0.1.0__py2.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.

Potentially problematic release.


This version of smartmodels might be problematic. Click here for more details.

@@ -0,0 +1,5 @@
1
+ """Top-level package for SmartModels."""
2
+
3
+ __author__ = """Asterio Gonzalez"""
4
+ __email__ = 'asterio.gonzalez@gmail.com'
5
+ __version__ = '0.1.0'
@@ -0,0 +1,36 @@
1
+ """CLI for 'SmartModels' package.
2
+
3
+ # Autocompletion
4
+
5
+ https://click.palletsprojects.com/en/8.1.x/shell-completion/
6
+
7
+ _SMARTMODELS_COMPLETE=bash_source smartmodels > ~/.smartmodels-complete.bash
8
+
9
+ . ~/.smartmodels-complete.bash
10
+
11
+ """
12
+ import sys
13
+ import os
14
+
15
+ # -----------------------------------------------
16
+ # import main cli interface (root)
17
+ # -----------------------------------------------
18
+
19
+ from .main import *
20
+ from .config import *
21
+ from .workspace import *
22
+
23
+ # -----------------------------------------------
24
+ # import other project submodules/subcommands
25
+ # -----------------------------------------------
26
+
27
+ # from .inventory import inventory
28
+ # from .plan import plan
29
+ # from .real import real
30
+ # from .roles import role
31
+ # from .run import run
32
+ # from .target import target
33
+ # from .test import test
34
+ # from .users import user
35
+ # from .watch import watch
36
+
@@ -0,0 +1,151 @@
1
+ import os
2
+ import yaml
3
+
4
+ import click
5
+
6
+ from ..helpers import *
7
+ from .main import *
8
+
9
+ # https://stackoverflow.com/questions/4842424/list-of-ansi-color-escape-sequences
10
+ RED = "\033[31;1;4m"
11
+ GREEN = "\033[32;1;4m"
12
+ YELLOW = "\033[33;1;4m"
13
+ BLUE = "\033[34;1;4m"
14
+ PINK = "\033[35;1;4m"
15
+
16
+ RESET = "\033[0m"
17
+
18
+
19
+ @main.group(context_settings=CONTEXT_SETTINGS)
20
+ @click.pass_obj
21
+ def config(env):
22
+ """A new group named 'config' nested to 'main' group
23
+ Whenever a 'config' subcommand is called, this code
24
+ will be executed before and load or create a config file
25
+ by default.
26
+ """
27
+
28
+ try:
29
+ load_config(env)
30
+
31
+ except Exception as why:
32
+ # If load_config fails, then create a clean one.
33
+ print(f"{why}")
34
+
35
+
36
+ setdefault(
37
+ env,
38
+ "includes",
39
+ {
40
+ r"smartmodels/.*\.yaml$": None,
41
+ },
42
+ )
43
+ setdefault(
44
+ env,
45
+ "excludes",
46
+ {},
47
+ )
48
+ setdefault(
49
+ env,
50
+ "folders", # Not regexp
51
+ {
52
+ #'~/Documents': None,
53
+ #'~/workspace': None,
54
+ ".": None,
55
+ },
56
+ )
57
+ setdefault(
58
+ env,
59
+ "resource",
60
+ os.path.join(env.home, "resources.yaml"),
61
+ )
62
+ setdefault(
63
+ env,
64
+ "role",
65
+ os.path.join(env.home, "roles.yaml"),
66
+ )
67
+ # if old != env.__dict__:
68
+ # save_config(env)
69
+
70
+ save_config(env)
71
+ return env
72
+
73
+
74
+ @config.command()
75
+ @click.pass_obj
76
+ def list(env):
77
+ banner("Config", env.__dict__)
78
+
79
+
80
+ @config.command()
81
+ @click.option("--include", default=None)
82
+ @click.option("--exclude", default=None)
83
+ @click.option("--folder", default=None)
84
+ @click.pass_obj
85
+ def view(env, include, exclude, folder):
86
+ if include:
87
+ click.echo(f"add include: {include}")
88
+ s = setdefault(env, "includes", dict())
89
+ s[include] = None
90
+ save_config(env)
91
+ if exclude:
92
+ click.echo(f"add exclude: {exclude}")
93
+ s = setdefault(env, "excludes", dict())
94
+ s[exclude] = None
95
+ save_config(env)
96
+ if folder:
97
+ click.echo(f"add folder: {folder}")
98
+ s = setdefault(env, "folders", dict())
99
+ s[folder] = None
100
+ save_config(env)
101
+ list.callback()
102
+
103
+
104
+
105
+
106
+ @config.command()
107
+ @click.option("--include", default=None)
108
+ @click.option("--exclude", default=None)
109
+ @click.option("--folder", default=None)
110
+ @click.pass_obj
111
+ def add(env, include, exclude, folder):
112
+ if include:
113
+ click.echo(f"add include: {include}")
114
+ s = setdefault(env, "includes", dict())
115
+ s[include] = None
116
+ save_config(env)
117
+ if exclude:
118
+ click.echo(f"add exclude: {exclude}")
119
+ s = setdefault(env, "excludes", dict())
120
+ s[exclude] = None
121
+ save_config(env)
122
+ if folder:
123
+ click.echo(f"add folder: {folder}")
124
+ s = setdefault(env, "folders", dict())
125
+ s[folder] = None
126
+ save_config(env)
127
+ list.callback()
128
+
129
+
130
+ @config.command()
131
+ @click.option("--include", default=None)
132
+ @click.option("--exclude", default=None)
133
+ @click.option("--folder", default=None)
134
+ @click.pass_obj
135
+ def delete(env, include, exclude, folder):
136
+ if include:
137
+ click.echo(f"delete include: {include}")
138
+ s = setdefault(env, "includes", dict())
139
+ s.pop(include, None)
140
+ save_config(env)
141
+ if exclude:
142
+ click.echo(f"add exclude: {exclude}")
143
+ s = setdefault(env, "excludes", dict())
144
+ s.pop(exclude, None)
145
+ save_config(env)
146
+ if folder:
147
+ click.echo(f"add folder: {folder}")
148
+ s = setdefault(env, "folders", dict())
149
+ s.pop(folder, None)
150
+ save_config(env)
151
+ list.callback()
@@ -0,0 +1,57 @@
1
+ """Console script for any click extensible CLI."""
2
+ import os
3
+ import click
4
+
5
+ CONTEXT_SETTINGS = dict(default_map={'runserver': {'port': 5000}})
6
+
7
+
8
+ class Env(object):
9
+ def __init__(self, home=None, debug=False):
10
+ home = os.path.expandvars(home)
11
+ home = os.path.expanduser(home)
12
+ home = os.path.abspath(home)
13
+
14
+ self.home = os.path.abspath(home)
15
+ self.cwd = os.path.abspath('.')
16
+ if self.cwd != self.home:
17
+ self.config_folders = [self.cwd, self.home]
18
+ else:
19
+ self.config_folders = [self.cwd]
20
+
21
+ self.config_files = [
22
+ os.path.join(path, 'config.yaml') for path in self.config_folders
23
+ ]
24
+
25
+ self.folders = []
26
+ self.debug = debug
27
+ self.autoassign_pattern = r'z.*\d+@'
28
+
29
+
30
+ @click.group(context_settings=CONTEXT_SETTINGS)
31
+ @click.option('--config-folder', envvar='SMARTMODELS_HOME', default='~/.config/smartmodels')
32
+ @click.option('--debug/--no-debug', default=False, envvar='REPO_DEBUG')
33
+ @click.pass_context
34
+ def main(ctx, config_folder, debug):
35
+ ctx.obj = Env(config_folder, debug)
36
+
37
+
38
+ @main.command()
39
+ @click.option('--port', default=8000)
40
+ @click.pass_obj
41
+ def add(env, port):
42
+ click.echo(f"Env: {env}/")
43
+ click.echo(f"Serving on http://127.0.0.1:{port}/")
44
+
45
+
46
+ @main.command()
47
+ @click.option('--port', default=8000)
48
+ @click.pass_obj
49
+ def delete(env, port):
50
+ click.echo(f"Serving on http://127.0.0.1:{port}/")
51
+
52
+
53
+ @main.command()
54
+ @click.option('--port', default=8000)
55
+ @click.pass_obj
56
+ def run(env, port):
57
+ click.echo(f"Serving on http://127.0.0.1:{port}/")
@@ -0,0 +1,159 @@
1
+ import re
2
+ import time
3
+ import subprocess
4
+
5
+ import sys
6
+
7
+ from distutils import command
8
+
9
+ # import os
10
+ import requests
11
+
12
+ # import yaml
13
+
14
+ import click
15
+
16
+ # from pycelium.tools import soft
17
+ # from pycelium.tools.cli.inventory import credentials, expand_network
18
+ # from pycelium.tools.cli.config import (
19
+ # # config,
20
+ # # banner,
21
+ # RED,
22
+ # RESET,
23
+ # BLUE,
24
+ # PINK,
25
+ # YELLOW,
26
+ # GREEN,
27
+ # )
28
+ from .main import *
29
+ from .config import *
30
+ from ..helpers import ConfigHelper
31
+
32
+
33
+ @main.group(context_settings=CONTEXT_SETTINGS)
34
+ @click.pass_obj
35
+ def setup(env):
36
+ """subcommands for manage workspaces for smartmodels"""
37
+ # banner("User", env.__dict__)
38
+ pass
39
+
40
+
41
+ def find_venv():
42
+ for path in sys.path:
43
+ m = re.match(
44
+ r"(?P<virtualenv>.*/(venv|env|virtualenv))/lib/python[^/]+/(site-packages)$",
45
+ path,
46
+ )
47
+ if m:
48
+ return m.groupdict()["virtualenv"]
49
+
50
+
51
+ def configure_unit(unit_content, service_name, service_type="service", restart=True):
52
+ # Write the service unit to a file
53
+ _tmp_file = f"/tmp/{service_name}.{service_type}"
54
+ unit_file_path = f"/etc/systemd/system/{service_name}.{service_type}"
55
+ with open(_tmp_file, "w") as unit_file:
56
+ unit_file.write(unit_content)
57
+ subprocess.run(["sudo", "mv", _tmp_file, unit_file_path])
58
+
59
+ # Reload systemd to apply changes
60
+ subprocess.run(["sudo", "systemctl", "daemon-reload"])
61
+
62
+ # Enable and start the service
63
+ subprocess.run(["sudo", "systemctl", "enable", service_name])
64
+ if restart:
65
+ subprocess.run(["sudo", "systemctl", "restart", service_name])
66
+
67
+
68
+ def _service(env, command):
69
+ """List existing workspaces for smartmodels"""
70
+
71
+ # Specify the service name
72
+ service_name = __file__.split("/")[-3]
73
+
74
+ # user and group
75
+ user = group = os.getlogin()
76
+ home_dir = os.path.expanduser("~")
77
+ # where is executable
78
+ virtualenv = find_venv()
79
+
80
+ if virtualenv is not None:
81
+ exec_start = (
82
+ f"{virtualenv}/bin/python {virtualenv}/bin/{service_name} {command}"
83
+ )
84
+ environment = f"Environment='PATH={virtualenv}/bin'"
85
+ else:
86
+ exec_start = f"{home_dir}/.local/bin/{service_name} {command}"
87
+ environment = ""
88
+
89
+ # Define the service unit configuration
90
+ service_unit = f"""
91
+ [Unit]
92
+ Description=smartmodels Supervisor Service
93
+ After=network.target
94
+
95
+ [Service]
96
+ ExecStart={exec_start}
97
+ {environment}
98
+
99
+ ProtectHome=false
100
+ WorkingDirectory={home_dir}/workspace/{service_name}
101
+ #Restart=always
102
+ Restart=no
103
+ #RestartSec=5s
104
+ User={user}
105
+ Group={group}
106
+
107
+ [Install]
108
+ WantedBy=multi-user.target
109
+ """
110
+
111
+ timer_unit = f"""
112
+ [Unit]
113
+ Description=smartmodels reset
114
+
115
+ [Timer]
116
+ Unit={service_name}.service
117
+ #OnCalendar=hourly
118
+ #OnCalendar=*:0/30
119
+ #OnCalendar=*:0/5
120
+
121
+ #OnBootSec=10min
122
+ #RandomizedDelaySec=15min
123
+ #OnActiveSec=15min
124
+ #OnCalendar=*-*-* 0/8:00:00
125
+ OnCalendar=*-*-* 00:00:00
126
+
127
+ [Install]
128
+ WantedBy=timers.target
129
+ """
130
+
131
+ configure_unit(service_unit, service_name, restart=False)
132
+ configure_unit(timer_unit, service_name, service_type="timer")
133
+
134
+
135
+ @setup.command()
136
+ @click.option("--command")
137
+ @click.pass_obj
138
+ def service(env, command):
139
+ """Install a reset service smartmodels"""
140
+ # force config loading
141
+ config.callback()
142
+
143
+ _service(env, command)
144
+
145
+
146
+ @setup.command()
147
+ @click.pass_obj
148
+ def autocomplete(env):
149
+ """Create bash auto-completion script"""
150
+ # force config loading
151
+ config.callback()
152
+ subprocess.run(
153
+ [
154
+ "_SMARTMODELS_COMPLETE=bash_source smartmodels > ~/.smartmodels-complete.bash"
155
+ ],
156
+ shell=True,
157
+ )
158
+ print("for activation use:")
159
+ print("source ~/.smartmodels-complete.bash")
@@ -0,0 +1,2 @@
1
+
2
+ """WingIDE remote support disabled"""
@@ -0,0 +1,119 @@
1
+ import re
2
+ import os
3
+ import yaml
4
+
5
+ import click
6
+
7
+ from .main import *
8
+ from .config import *
9
+
10
+ @main.group(context_settings=CONTEXT_SETTINGS)
11
+ @click.pass_obj
12
+ def workspace(env):
13
+ """subcommands for manae workspaces for smartmodels"""
14
+ # banner("User", env.__dict__)
15
+ pass
16
+
17
+
18
+ @workspace.command()
19
+ @click.option("--path", default=None)
20
+ @click.pass_obj
21
+ def new(env, path):
22
+ """Create a new workspace for smartmodels"""
23
+ # force config loading
24
+ config.callback()
25
+
26
+ # TODO: add your new workspace configuratoin folder here ...
27
+ if not path:
28
+ path = "."
29
+
30
+ root = expandpath(path)
31
+ print(f"Creating / updating workspace in {root}")
32
+ os.makedirs(root, exist_ok=True)
33
+
34
+ # database for stats
35
+ stats_path = os.path.join(root, 'stats.yaml')
36
+ gitlab_cfg_path = os.path.join(root, '.python-gitlab.cfg')
37
+ db_path = os.path.join(root, 'db')
38
+ if not os.path.exists(stats_path):
39
+ db = {
40
+ 'kpi_1': 0.73,
41
+ 'kpi_2': 0,
42
+ }
43
+ yaml.dump(db, open(stats_path, 'wt'), Dumper=yaml.Dumper)
44
+
45
+ # config file
46
+ config_path = os.path.join(root, 'config.yaml')
47
+ if not os.path.exists(config_path):
48
+ db = {
49
+ 'templates': {
50
+ 'compiled': {
51
+ '{root}/{reldir}/compiled/{basename}.json': [
52
+ r'(?P<dirname>.*)[/\/](?P<basename>(?P<name>.*?)(?P<ext>\.[^\.]+$))'
53
+ ],
54
+ },
55
+ 'error': {
56
+ '{root}/error/{reldir}/{basename}': [
57
+ r'(?P<dirname>.*)[/\/](?P<basename>(?P<name>.*?)(?P<ext>\.[^\.]+$))'
58
+ ],
59
+ },
60
+ },
61
+ 'stats': stats_path,
62
+ 'db': db_path,
63
+ 'folders': {
64
+ 'data': f'{root}/data/',
65
+ },
66
+ 'gitlab_cfg_path': gitlab_cfg_path,
67
+ 'gitlab_instance': 'spec',
68
+ 'num_threads': 8,
69
+ }
70
+ yaml.dump(db, open(config_path, 'wt'), Dumper=yaml.Dumper)
71
+
72
+ # check folder in config file
73
+ cfg = yaml.load(open(config_path, 'rt'), Loader=yaml.Loader)
74
+
75
+ # create working folders
76
+ for name in cfg['folders'].values():
77
+ path = os.path.join(root, name)
78
+ os.makedirs(path, exist_ok=True)
79
+
80
+ # check .env file
81
+ env_path = os.path.join(root, '.env')
82
+ if not os.path.exists(env_path):
83
+ content = f"""# ENV variables
84
+ PYTHON_GITLAB_CFG={gitlab_cfg_path}
85
+ OPENAI_API_KEY=
86
+ """
87
+ open(env_path, 'wt').write(content)
88
+
89
+ # check gitlab_cfg_path file
90
+ if not os.path.exists(gitlab_cfg_path):
91
+ content = f"""
92
+ [global]
93
+ default = spec
94
+ ssl_verify = true
95
+ timeout = 10
96
+
97
+ [spec]
98
+ url = https://git.spec-cibernos.com
99
+ private_token = glpat-ZZ_TDbasg1CsyCsa4ihG
100
+ api_version = 4
101
+
102
+ [elsewhere]
103
+ url = http://else.whe.re:8080
104
+ private_token = helper: path/to/helper.sh
105
+ timeout = 1
106
+ """
107
+ open(gitlab_cfg_path, 'wt').write(content)
108
+
109
+
110
+ @workspace.command()
111
+ @click.pass_obj
112
+ def list(env):
113
+ """List existing workspaces for smartmodels"""
114
+ # force config loading
115
+ config.callback()
116
+
117
+ # TODO: add your new workspace configuration folder here ...
118
+
119
+
smartmodels/helpers.py ADDED
@@ -0,0 +1,248 @@
1
+ import os
2
+ import yaml
3
+
4
+ import string
5
+ from datetime import timedelta
6
+ from dateutil import parser
7
+ from glom import glom, assign
8
+ #import jmespath
9
+
10
+
11
+ # ------------------------------------------------
12
+ # File and config helpers
13
+ # ------------------------------------------------
14
+ def expandpath(path):
15
+ if path:
16
+ path = os.path.expanduser(path)
17
+ path = os.path.expandvars(path)
18
+ path = os.path.abspath(path)
19
+ while path[-1] == "/":
20
+ path = path[:-1]
21
+ return path
22
+
23
+ def load_config(env):
24
+ """Merge config files"""
25
+ cfg = env.__dict__
26
+ for path in reversed(env.config_files):
27
+ try:
28
+ data = yaml.load(open(path, "rt"), Loader=yaml.Loader)
29
+ # merge(cfg, data, inplace=True) # use any deep merge library or ...
30
+ cfg.update(data)
31
+
32
+ except FileNotFoundError:
33
+ pass
34
+
35
+ env.folders = {expandpath(p): None for p in env.folders}
36
+
37
+
38
+ def save_config(env):
39
+ os.makedirs(os.path.dirname(env.config_file), exist_ok=True)
40
+ yaml.dump(env.__dict__, open(env.config_file, "wt"))
41
+
42
+
43
+
44
+ # --------------------------------------------------
45
+ # Convert Base
46
+ # --------------------------------------------------
47
+
48
+ # CHAR_LOOKUP = list(string.digits + string.ascii_letters)
49
+
50
+ # avoid use of numbers (so can be used as regular attribute names with ".")
51
+ CHAR_LOOKUP = list(string.ascii_letters)
52
+ INV_LOOKUP = {c: i for i, c in enumerate(CHAR_LOOKUP)}
53
+
54
+
55
+ def convert_base(number, base, padding=-1, lookup=CHAR_LOOKUP):
56
+ """Coding a number into a string in base 'base'
57
+
58
+ results will be padded with '0' until minimal 'padding'
59
+ length is reached.
60
+
61
+ lookup is the char map available for coding.
62
+ """
63
+ if base < 2 or base > len(lookup):
64
+ raise RuntimeError(
65
+ f"base: {base} > coding map length: {len(lookup)}"
66
+ )
67
+ mods = []
68
+ while number > 0:
69
+ mods.append(lookup[number % base])
70
+ number //= base
71
+
72
+ while len(mods) < padding:
73
+ mods.append(lookup[0])
74
+
75
+ mods.reverse()
76
+ return ''.join(mods)
77
+
78
+
79
+ def from_base(key, base, inv_lookup=INV_LOOKUP):
80
+ """Convert a coded number in base 'base' to an integer."""
81
+ number = 0
82
+ keys = list(key)
83
+ keys.reverse()
84
+ w = 1
85
+ for c in keys:
86
+ number += INV_LOOKUP[c] * w
87
+ w *= base
88
+ return number
89
+
90
+
91
+ # def new_uid(base=50):
92
+ # number = uuid.uuid1()
93
+ # return convert_base(number.int, base)
94
+ SEED = 12345
95
+
96
+
97
+ def new_uid(base=50):
98
+ global SEED
99
+ SEED += 1
100
+ return convert_base(SEED, base)
101
+
102
+
103
+ # from xml.sax.saxutils import escape
104
+ # ------------------------------------------------
105
+ # jinja2 filters
106
+ # ------------------------------------------------
107
+ def escape(text: str):
108
+ text = text.replace("&", "&amp;")
109
+ text = text.replace("<", "&lt;")
110
+ text = text.replace(">", "&gt;")
111
+ text = text.replace('"', "&quot;")
112
+ text = text.replace("'", "&apos;")
113
+ return text
114
+
115
+
116
+ def fmt(value, fmt=">40"):
117
+ fmt = "{:" + fmt + "}"
118
+ try:
119
+ value = fmt.format(value)
120
+ except:
121
+ pass
122
+ return value
123
+
124
+
125
+
126
+
127
+ # ------------------------------------------------
128
+ # glom extensions
129
+ # ------------------------------------------------
130
+ def setdefault(obj, path, val, missing=dict):
131
+ current = glom(obj, path, default=None)
132
+ if current is None:
133
+ assign(obj, path, val, missing=missing)
134
+ return val
135
+ return current
136
+
137
+
138
+ # ------------------------------------------------
139
+ # Converter functions
140
+ # ------------------------------------------------
141
+ def I(x):
142
+ return x
143
+
144
+
145
+ def INT(x):
146
+ return int(x)
147
+
148
+
149
+ def FLOAT(x):
150
+ return float(x)
151
+
152
+
153
+ def BOOL(x):
154
+ return x.lower() in ("true", "yes")
155
+
156
+
157
+ def TEXT(x):
158
+ return x.text
159
+
160
+
161
+ def DATE(x): # TODO
162
+ return parser.parse(x)
163
+
164
+
165
+ def DURATION(x): # TODO
166
+ return timedelta(days=float(x))
167
+
168
+
169
+ def COLOR(x):
170
+ """Task color
171
+ Ignore when if a "black" or "blue" color and let GP
172
+ use default ones next time.
173
+ """
174
+ if x not in ("#8cb6ce", "#000000"):
175
+ return x
176
+ return x # TODO: remove, this hack will remove default colors
177
+
178
+
179
+ def PRIORITY(x):
180
+ """GanttProject PRIORITY.... (have not sense :) )"""
181
+ return {
182
+ "3": -2, # Lowest
183
+ "0": -1, # Low
184
+ None: 0, # Normal (missing)
185
+ "2": 1, # High
186
+ "4": 2, # Highest
187
+ }.get(x, 0)
188
+
189
+
190
+ # ------------------------------------------------
191
+ # console
192
+ # ------------------------------------------------
193
+
194
+ GREEN = "\033[32;1;4m"
195
+ RESET = "\033[0m"
196
+
197
+
198
+ last_sepatator = 40
199
+
200
+
201
+ def banner(
202
+ header,
203
+ lines=None,
204
+ spec=None,
205
+ sort_by=None,
206
+ sort_reverse=True,
207
+ output=print,
208
+ color=GREEN,
209
+ ):
210
+ global last_sepatator
211
+ lines = lines or []
212
+ # compute keys spaces
213
+ m = 1 + max([len(k) for k in lines] or [0])
214
+ if isinstance(lines, dict):
215
+ if sort_by:
216
+ idx = 0 if sort_by.lower().startswith("keys") else 1
217
+ lines = dict(
218
+ sorted(
219
+ lines.items(),
220
+ key=lambda item: item[idx],
221
+ reverse=sort_reverse,
222
+ )
223
+ )
224
+ _lines = []
225
+ for k, v in lines.items():
226
+ if spec:
227
+ try:
228
+ v = glom(v, spec)
229
+ except:
230
+ v = getattr(v, spec)
231
+
232
+ line = f"{k.ljust(m)}: {v}"
233
+ _lines.append(line)
234
+ lines = _lines
235
+
236
+ if lines:
237
+ m = max([len(l) for l in lines])
238
+ last_sepatator = m
239
+ elif last_sepatator:
240
+ m = last_sepatator
241
+ else:
242
+ m = max([40, len(header)]) - len(header) + 1
243
+
244
+ # m = max([len(l) for l in lines] or [40, len(header)]) - len(header) + 1
245
+ output(f"{color}{header}{' ' * m}{RESET}")
246
+ for line in lines:
247
+ output(line)
248
+
@@ -0,0 +1,31 @@
1
+ """Main module."""
2
+
3
+ # libraty modules
4
+ import asyncio
5
+ import os
6
+
7
+ # library partial
8
+ from time import sleep
9
+
10
+
11
+ # local imports
12
+ from .helpers import parse_uri
13
+
14
+ # 3rd party libraries
15
+
16
+
17
+ # ---------------------------------------------------------
18
+ # Loggers
19
+ # ---------------------------------------------------------
20
+
21
+ from agptools.logs import logger
22
+
23
+ log = logger(__name__)
24
+
25
+ # subloger = logger(f'{__name__}.subloger')
26
+
27
+
28
+ # =========================================================
29
+ # smartmodels
30
+ # =========================================================
31
+
@@ -0,0 +1,13 @@
1
+ =======
2
+ Credits
3
+ =======
4
+
5
+ Development Lead
6
+ ----------------
7
+
8
+ * Asterio Gonzalez <asterio.gonzalez@gmail.com>
9
+
10
+ Contributors
11
+ ------------
12
+
13
+ None yet. Why not be the first?
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024, Asterio Gonzalez
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
@@ -0,0 +1,87 @@
1
+ Metadata-Version: 2.1
2
+ Name: smartmodels
3
+ Version: 0.1.0
4
+ Summary: Smart Models for FIWARE
5
+ Home-page: https://github.com/asterio/smartmodels
6
+ Author: Asterio Gonzalez
7
+ Author-email: asterio.gonzalez@gmail.com
8
+ License: MIT license
9
+ Keywords: smartmodels
10
+ Platform: UNKNOWN
11
+ Classifier: Development Status :: 2 - Pre-Alpha
12
+ Classifier: Intended Audience :: Developers
13
+ Classifier: License :: OSI Approved :: MIT License
14
+ Classifier: Natural Language :: English
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3.9
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Requires-Python: >=3.6
20
+ License-File: LICENSE
21
+ License-File: AUTHORS.rst
22
+ Requires-Dist: Click (>=7.1.2)
23
+ Requires-Dist: agptools
24
+ Requires-Dist: glom
25
+ Requires-Dist: jmespath
26
+
27
+ ===========
28
+ SmartModels
29
+ ===========
30
+
31
+
32
+ .. image:: https://img.shields.io/pypi/v/smartmodels.svg
33
+ :target: https://pypi.python.org/pypi/smartmodels
34
+
35
+ .. image:: https://img.shields.io/travis/asterio/smartmodels.svg
36
+ :target: https://travis-ci.com/asterio/smartmodels
37
+
38
+ .. image:: https://readthedocs.org/projects/smartmodels/badge/?version=latest
39
+ :target: https://smartmodels.readthedocs.io/en/latest/?version=latest
40
+ :alt: Documentation Status
41
+
42
+
43
+
44
+
45
+ Smart Models for FIWARE
46
+
47
+
48
+ * Free software: MIT license
49
+ * Documentation: https://smartmodels.readthedocs.io.
50
+
51
+
52
+ Features
53
+ ----------------
54
+
55
+ * TODO
56
+
57
+ Before Coding
58
+ ----------------
59
+
60
+ * create a virtual env
61
+
62
+ ::
63
+ python3 -m venv venv
64
+ source venv/bin/activate
65
+ make install-testing-requisites
66
+
67
+
68
+
69
+ Credits
70
+ ----------------
71
+
72
+ This package was created with Cookiecutter_ and the `cib_pypackage`_ project template.
73
+
74
+ .. _Cookiecutter: https://github.com/audreyr/cookiecutter
75
+ .. _`cib_pypackage`: https://git.spec-cibernos.com/spec/templates/cib_pypackage
76
+
77
+
78
+ =======
79
+ History
80
+ =======
81
+
82
+ 0.1.0 (2024-02-07)
83
+ ------------------
84
+
85
+ * First release on PyPI.
86
+
87
+
@@ -0,0 +1,16 @@
1
+ smartmodels/__init__.py,sha256=VnqJPLI4i4souu-742WRkiubW1wNveWpWb6e3478sec,141
2
+ smartmodels/helpers.py,sha256=n-NWprHyIrqg7s-N6Bh6t05sawbAH-i10C4WAFaN3y4,5708
3
+ smartmodels/smartmodels.py,sha256=75tOPm5n51W8M37lqFcsQZ-2jHmq3V0KTVqMCdvECsU,550
4
+ smartmodels/cli/__init__.py,sha256=HcpquBnPgYbtDEQ1zYCIXXYRVLcMOzW89uS6kpLKFpQ,844
5
+ smartmodels/cli/config.py,sha256=1jNso7I0tNwDnwZu3SsvFMgmCL2nznGZ2z9Lr51iCsE,3711
6
+ smartmodels/cli/main.py,sha256=Cq2Vb-CiTtGT66G10BC7CwUdzeQkiS9SkmcsPFlAC7Y,1565
7
+ smartmodels/cli/setup.py,sha256=lTfh6KY5Md_SqzDMXLafulH0txDMwv85LWU_ATUXwMw,3625
8
+ smartmodels/cli/wingdbstub.py,sha256=3jzRnyg351_Z898pxFfEZvfr93m3msCf4rQYBAKMRjQ,39
9
+ smartmodels/cli/workspace.py,sha256=p0ELSARq77TBED8kuSyFg9h8LZavswWuX03q52gbFbE,3127
10
+ smartmodels-0.1.0.dist-info/AUTHORS.rst,sha256=3ZPoqg8Aav8DSYKd0fwcwn4_5HwSiMLart0E5Un00-U,168
11
+ smartmodels-0.1.0.dist-info/LICENSE,sha256=JqzQ9S4hVjQBOM8SiUG9-qhokt1oKfE2qJMRNa3t410,1075
12
+ smartmodels-0.1.0.dist-info/METADATA,sha256=FYCWynOhbGdaEUxMhm-BI0hjl9yMxh0MYvPoAV4W0z8,1926
13
+ smartmodels-0.1.0.dist-info/WHEEL,sha256=z9j0xAa_JmUKMpmz72K0ZGALSM_n-wQVmGbleXx2VHg,110
14
+ smartmodels-0.1.0.dist-info/entry_points.txt,sha256=kZrQd6boeTe5YikNYC_L22M7UMuoBQeHwD8SF8BEGiI,54
15
+ smartmodels-0.1.0.dist-info/top_level.txt,sha256=OdN-SOwhQYptkH0_ZYMAtsC3UmQ3MhZ9neK26CNLx0A,12
16
+ smartmodels-0.1.0.dist-info/RECORD,,
@@ -0,0 +1,6 @@
1
+ Wheel-Version: 1.0
2
+ Generator: bdist_wheel (0.37.1)
3
+ Root-Is-Purelib: true
4
+ Tag: py2-none-any
5
+ Tag: py3-none-any
6
+
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ smartmodels = smartmodels.cli:main
3
+
@@ -0,0 +1 @@
1
+ smartmodels