neo-data-svc 0.1.0__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.

Potentially problematic release.


This version of neo-data-svc might be problematic. Click here for more details.

@@ -0,0 +1,86 @@
1
+ __pycache__/
2
+ *.py[cod]
3
+ *$py.class
4
+
5
+ *.so
6
+
7
+ .Python
8
+ env/
9
+ build/
10
+ develop-eggs/
11
+ dist/
12
+ downloads/
13
+ eggs/
14
+ .eggs/
15
+ lib/
16
+ lib64/
17
+ parts/
18
+ sdist/
19
+ var/
20
+ wheels/
21
+ *.egg-info/
22
+ .installed.cfg
23
+ *.egg
24
+
25
+ *.manifest
26
+ *.spec
27
+
28
+ pip-log.txt
29
+ pip-delete-this-directory.txt
30
+
31
+ htmlcov/
32
+ .tox/
33
+ .coverage
34
+ .coverage.*
35
+ .cache
36
+ nosetests.xml
37
+ coverage.xml
38
+ *.cover
39
+ .hypothesis/
40
+ .pytest_cache/
41
+
42
+ *.mo
43
+ *.pot
44
+
45
+ *.log
46
+ local_settings.py
47
+
48
+ instance/
49
+ .webassets-cache
50
+
51
+ .scrapy
52
+
53
+ docs/_build/
54
+
55
+ target/
56
+
57
+ .ipynb_checkpoints
58
+
59
+ dask-worker-space/
60
+
61
+ .python-version
62
+
63
+ celerybeat-schedule
64
+
65
+ *.sage.py
66
+
67
+ .env
68
+
69
+ .venv
70
+ venv/
71
+ ENV/
72
+
73
+ .spyderproject
74
+ .spyproject
75
+
76
+ .ropeproject
77
+
78
+ /site
79
+
80
+ .mypy_cache/
81
+
82
+ .vscode/
83
+ .idea/
84
+
85
+ src/emdm/files/
86
+ uv.lock
@@ -0,0 +1,12 @@
1
+ Metadata-Version: 2.4
2
+ Name: neo-data-svc
3
+ Version: 0.1.0
4
+ Summary: A data base svc
5
+ Author-email: Eric <email@example.com>
6
+ License: Proprietary
7
+ Requires-Python: >=3.12.3
8
+ Requires-Dist: delta-spark==2.4.0
9
+ Requires-Dist: pyspark==3.4.4
10
+ Description-Content-Type: text/markdown
11
+
12
+ # neo-data-svc
@@ -0,0 +1 @@
1
+ # neo-data-svc
@@ -0,0 +1,28 @@
1
+ [project]
2
+ name = "neo-data-svc"
3
+ version = "0.1.0"
4
+ description = "A data base svc"
5
+ authors = [
6
+ {name = "Eric", email = "email@example.com"},
7
+ ]
8
+ readme = "README.md"
9
+ requires-python = ">=3.12.3"
10
+ license = {text = "Proprietary"}
11
+
12
+ dependencies = [
13
+ "pyspark==3.4.4",
14
+ "delta-spark==2.4.0",
15
+ ]
16
+
17
+ [build-system]
18
+ requires = ["hatchling"]
19
+ build-backend = "hatchling.build"
20
+
21
+ [tool.pyright]
22
+ reportMissingImports = false
23
+ reportPrivateImportUsage = false
24
+ reportUndefinedVariable = false
25
+ enableTypeIgnoreComments = true
26
+ reportPrivateUsage = false
27
+ reportGeneralTypeIssues = false
28
+ reportWildcardImportFromLibrary = false
@@ -0,0 +1,8 @@
1
+ __version__ = "0.1.0"
2
+
3
+ from .core import get_session, install
4
+
5
+ install()
6
+
7
+ S, Q = get_session()
8
+ __all__ = ["S", "Q"]
@@ -0,0 +1,59 @@
1
+ import logging
2
+
3
+ from delta.tables import DeltaTable
4
+ from pyspark.sql import DataFrame
5
+
6
+ from .session import M
7
+
8
+ logger = logging.getLogger(__name__)
9
+
10
+
11
+ def neo_write(self, path, mode="overwrite", keys=None, **options):
12
+ writer = self.write.format("delta")
13
+
14
+ for key, value in options.items():
15
+ writer = writer.option(key, value)
16
+
17
+ try:
18
+ if mode == "overwrite":
19
+ writer.mode("overwrite").save(path)
20
+
21
+ elif mode == "append":
22
+ writer.mode("append").save(path)
23
+
24
+ elif mode == "merge":
25
+ if not keys:
26
+ raise ValueError("keys required for merge mode")
27
+
28
+ delta_table = DeltaTable.forPath(self.sparkSession, path)
29
+ condition = " AND ".join(
30
+ [f"target.{k} = source.{k}" for k in keys])
31
+
32
+ (delta_table.alias("target")
33
+ .merge(self.alias("source"), condition)
34
+ .whenMatchedUpdateAll()
35
+ .whenNotMatchedInsertAll()
36
+ .execute())
37
+
38
+ else:
39
+ raise ValueError(f"Unsupported mode: {mode}")
40
+
41
+ logger.info(f"Successfully wrote to {path} using {mode}")
42
+
43
+ except Exception as e:
44
+ if "Path does not exist" in str(e) and mode == "merge":
45
+ writer.mode("overwrite").save(path)
46
+ logger.info(f"Created new Delta table at {path}")
47
+ else:
48
+ raise
49
+
50
+
51
+ def install():
52
+ if not hasattr(DataFrame, 'neo_write'):
53
+ setattr(DataFrame, "neo_write", neo_write)
54
+
55
+ logger.info("Neo Data Service installed")
56
+
57
+
58
+ def get_session():
59
+ return M.get_session()
@@ -0,0 +1,95 @@
1
+ import importlib
2
+ import logging
3
+ import sys
4
+
5
+ from pyspark.sql import SparkSession
6
+
7
+ logger = logging.getLogger(__name__)
8
+
9
+
10
+ class M:
11
+ _instance = None
12
+ _config = None
13
+
14
+ @classmethod
15
+ def get_session(cls):
16
+ if cls._instance is None:
17
+ cls._init_session()
18
+
19
+ if cls._instance:
20
+ return (cls._instance, cls._instance.sql)
21
+
22
+ @classmethod
23
+ def _discover_config(cls):
24
+ if cls._config is not None:
25
+ return cls._config
26
+
27
+ stack = []
28
+ frame = sys._getframe()
29
+ for _ in range(6):
30
+ if frame is None:
31
+ return stack
32
+ frame = frame.f_back
33
+
34
+ while frame:
35
+ mod = frame.f_globals.get('__name__', '')
36
+ if mod and not mod.startswith('neo_data_svc'):
37
+ stack.append(mod)
38
+ frame = frame.f_back
39
+
40
+ logger.info(f"Import stack: {stack}")
41
+
42
+ config_paths = cls._generate_config_paths(stack)
43
+ config = {}
44
+
45
+ for path in config_paths:
46
+ try:
47
+ module = importlib.import_module(path)
48
+ cls._config = cls._parse_config(module, config)
49
+ logger.info(f"config from: {path}")
50
+ return cls._config
51
+ except ImportError as e:
52
+ logger.debug(f"Failed to import {path}: {e}")
53
+ continue
54
+
55
+ cls._config = config
56
+ return cls._config
57
+
58
+ @classmethod
59
+ def _generate_config_paths(cls, stack):
60
+ paths = []
61
+
62
+ for module_name in stack:
63
+ if '.' in module_name:
64
+ root_package = module_name.split('.')[0]
65
+ paths.extend([f"{root_package}.config.Cfg"])
66
+
67
+ unique_paths = list(dict.fromkeys(paths))
68
+ return unique_paths
69
+
70
+ @classmethod
71
+ def _parse_config(cls, module, base_config):
72
+ config = base_config.copy()
73
+
74
+ for attr_name in dir(module):
75
+ value = getattr(module, attr_name)
76
+ config[attr_name] = value
77
+ return config
78
+
79
+ @classmethod
80
+ def _init_session(cls):
81
+ config = cls._discover_config()
82
+ cls._instance = SparkSession.builder.appName(config['APP']).getOrCreate() # type: ignore
83
+
84
+ @classmethod
85
+ def get_config(cls):
86
+ if cls._config is None:
87
+ cls._discover_config()
88
+ return cls._config
89
+
90
+ @classmethod
91
+ def stop_session(cls):
92
+ if cls._instance:
93
+ cls._instance.stop()
94
+ cls._instance = None
95
+ cls._config = None