azure-discovery 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 (33) hide show
  1. {azure_discovery-0.1.0 → azure_discovery-0.1.2}/PKG-INFO +1 -1
  2. {azure_discovery-0.1.0 → azure_discovery-0.1.2}/azure_discovery/__init__.py +33 -33
  3. {azure_discovery-0.1.0 → azure_discovery-0.1.2}/azure_discovery/cli.py +3 -3
  4. azure_discovery-0.1.2/azure_discovery/utils/logging.py +86 -0
  5. {azure_discovery-0.1.0 → azure_discovery-0.1.2}/azure_discovery.egg-info/PKG-INFO +1 -1
  6. {azure_discovery-0.1.0 → azure_discovery-0.1.2}/pyproject.toml +116 -116
  7. azure_discovery-0.1.0/azure_discovery/utils/logging.py +0 -59
  8. {azure_discovery-0.1.0 → azure_discovery-0.1.2}/LICENSE +0 -0
  9. {azure_discovery-0.1.0 → azure_discovery-0.1.2}/README.md +0 -0
  10. {azure_discovery-0.1.0 → azure_discovery-0.1.2}/azure_discovery/adt_types/__init__.py +0 -0
  11. {azure_discovery-0.1.0 → azure_discovery-0.1.2}/azure_discovery/adt_types/errors.py +0 -0
  12. {azure_discovery-0.1.0 → azure_discovery-0.1.2}/azure_discovery/adt_types/models.py +0 -0
  13. {azure_discovery-0.1.0 → azure_discovery-0.1.2}/azure_discovery/api.py +0 -0
  14. {azure_discovery-0.1.0 → azure_discovery-0.1.2}/azure_discovery/enumerators/__init__.py +0 -0
  15. {azure_discovery-0.1.0 → azure_discovery-0.1.2}/azure_discovery/enumerators/azure_resources.py +0 -0
  16. {azure_discovery-0.1.0 → azure_discovery-0.1.2}/azure_discovery/orchestrator.py +0 -0
  17. {azure_discovery-0.1.0 → azure_discovery-0.1.2}/azure_discovery/reporting/__init__.py +0 -0
  18. {azure_discovery-0.1.0 → azure_discovery-0.1.2}/azure_discovery/reporting/console.py +0 -0
  19. {azure_discovery-0.1.0 → azure_discovery-0.1.2}/azure_discovery/reporting/html.py +0 -0
  20. {azure_discovery-0.1.0 → azure_discovery-0.1.2}/azure_discovery/utils/__init__.py +0 -0
  21. {azure_discovery-0.1.0 → azure_discovery-0.1.2}/azure_discovery/utils/azure_clients.py +0 -0
  22. {azure_discovery-0.1.0 → azure_discovery-0.1.2}/azure_discovery/utils/graph_helpers.py +0 -0
  23. {azure_discovery-0.1.0 → azure_discovery-0.1.2}/azure_discovery.egg-info/SOURCES.txt +0 -0
  24. {azure_discovery-0.1.0 → azure_discovery-0.1.2}/azure_discovery.egg-info/dependency_links.txt +0 -0
  25. {azure_discovery-0.1.0 → azure_discovery-0.1.2}/azure_discovery.egg-info/entry_points.txt +0 -0
  26. {azure_discovery-0.1.0 → azure_discovery-0.1.2}/azure_discovery.egg-info/requires.txt +0 -0
  27. {azure_discovery-0.1.0 → azure_discovery-0.1.2}/azure_discovery.egg-info/top_level.txt +0 -0
  28. {azure_discovery-0.1.0 → azure_discovery-0.1.2}/setup.cfg +0 -0
  29. {azure_discovery-0.1.0 → azure_discovery-0.1.2}/tests/test_azure_resources.py +0 -0
  30. {azure_discovery-0.1.0 → azure_discovery-0.1.2}/tests/test_graph_helpers.py +0 -0
  31. {azure_discovery-0.1.0 → azure_discovery-0.1.2}/tests/test_orchestrator.py +0 -0
  32. {azure_discovery-0.1.0 → azure_discovery-0.1.2}/tests/test_reporting_console.py +0 -0
  33. {azure_discovery-0.1.0 → azure_discovery-0.1.2}/tests/test_reporting_html.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: azure-discovery
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: Lightweight Azure tenant discovery and visualization via Resource Graph. Enumerates subscriptions and resources, normalizes results, and renders interactive dependency graphs. Supports public and sovereign clouds (Gov, China, Germany, Azure Stack).
5
5
  Author: David Frazer <david.frazer336@gmail.com>
6
6
  License-Expression: MIT
@@ -1,33 +1,33 @@
1
- """Azure Discovery: Azure tenant discovery and visualization via Resource Graph.
2
-
3
- This package can be installed from PyPI as ``azure-discovery`` and used as:
4
-
5
- pip install azure-discovery
6
- azure-discovery discover --tenant-id <id> --subscription <sub-id>
7
-
8
- Programmatic usage:
9
-
10
- from azure_discovery import run_discovery
11
- from azure_discovery.adt_types import AzureDiscoveryRequest, AzureDiscoveryResponse
12
- """
13
-
14
- from .orchestrator import run_discovery
15
- from .adt_types import (
16
- AzureDiscoveryRequest,
17
- AzureDiscoveryResponse,
18
- AzureEnvironment,
19
- DiscoveryFilter,
20
- ResourceNode,
21
- ResourceRelationship,
22
- )
23
-
24
- __all__ = [
25
- "run_discovery",
26
- "AzureDiscoveryRequest",
27
- "AzureDiscoveryResponse",
28
- "AzureEnvironment",
29
- "DiscoveryFilter",
30
- "ResourceNode",
31
- "ResourceRelationship",
32
- ]
33
- __version__ = "0.1.0"
1
+ """Azure Discovery: Azure tenant discovery and visualization via Resource Graph.
2
+
3
+ This package can be installed from PyPI as ``azure-discovery`` and used as:
4
+
5
+ pip install azure-discovery
6
+ azure-discovery discover --tenant-id <id> --subscription <sub-id>
7
+
8
+ Programmatic usage:
9
+
10
+ from azure_discovery import run_discovery
11
+ from azure_discovery.adt_types import AzureDiscoveryRequest, AzureDiscoveryResponse
12
+ """
13
+
14
+ from .orchestrator import run_discovery
15
+ from .adt_types import (
16
+ AzureDiscoveryRequest,
17
+ AzureDiscoveryResponse,
18
+ AzureEnvironment,
19
+ DiscoveryFilter,
20
+ ResourceNode,
21
+ ResourceRelationship,
22
+ )
23
+
24
+ __all__ = [
25
+ "run_discovery",
26
+ "AzureDiscoveryRequest",
27
+ "AzureDiscoveryResponse",
28
+ "AzureEnvironment",
29
+ "DiscoveryFilter",
30
+ "ResourceNode",
31
+ "ResourceRelationship",
32
+ ]
33
+ __version__ = "0.1.2"
@@ -17,7 +17,7 @@ from .adt_types import (
17
17
  DiscoveryFilter,
18
18
  VisualizationOptions,
19
19
  )
20
- from .utils.logging import get_logger
20
+ from .utils.logging import enable_cli_logging
21
21
 
22
22
  cli = typer.Typer(help="Azure tenant discovery and visualization CLI")
23
23
 
@@ -83,8 +83,8 @@ def discover_command(
83
83
  Use --quiet to suppress all logs except errors.
84
84
  """
85
85
 
86
- # Initialize logger with quiet mode
87
- get_logger(quiet=quiet)
86
+ # Emit logs to stderr only when run as CLI; library use stays silent.
87
+ enable_cli_logging(quiet=quiet)
88
88
 
89
89
  tag_filters = _parse_tags(required_tag)
90
90
  discovery_filter = DiscoveryFilter(
@@ -0,0 +1,86 @@
1
+ """Structured logging helpers.
2
+
3
+ When used as a library (e.g. imported by auto_iac), no handlers are attached
4
+ by default so the package does not write to stderr and does not interfere
5
+ with the calling application's UI (e.g. Rich live panels). Callers can attach
6
+ their own handler to the \"azure_discovery\" logger if they want to see logs.
7
+
8
+ When run as the CLI, the entrypoint calls enable_cli_logging() so logs are
9
+ emitted to stderr in JSON form.
10
+ """
11
+
12
+ from __future__ import annotations
13
+
14
+ import json
15
+ import logging
16
+ import os
17
+ import sys
18
+ from typing import Any, Dict
19
+
20
+ _LOGGER_NAME = "azure_discovery"
21
+
22
+
23
+ def _build_json_formatter() -> logging.Formatter:
24
+ class JsonFormatter(logging.Formatter):
25
+ def format(self, record: logging.LogRecord) -> str:
26
+ payload: Dict[str, Any] = {
27
+ "logger": record.name,
28
+ "level": record.levelname,
29
+ "message": record.getMessage(),
30
+ "module": record.module,
31
+ "function": record.funcName,
32
+ }
33
+ if record.exc_info:
34
+ payload["exc_info"] = self.formatException(record.exc_info)
35
+ if record.__dict__.get("context"):
36
+ payload["context"] = record.__dict__["context"]
37
+ return json.dumps(payload)
38
+
39
+ return JsonFormatter()
40
+
41
+
42
+ def get_logger(quiet: bool = False) -> logging.Logger:
43
+ """Return module-wide logger. Does not attach any handler when used as a library.
44
+
45
+ Library use: no output unless the calling app attaches a handler to
46
+ \"azure_discovery\". CLI use: call enable_cli_logging() first so logs go to stderr.
47
+
48
+ Args:
49
+ quiet: Ignored when no CLI handler is attached. When enable_cli_logging(quiet=True)
50
+ is used, only ERROR and above are emitted.
51
+ """
52
+ logger = logging.getLogger(_LOGGER_NAME)
53
+ if logger.handlers:
54
+ if quiet:
55
+ logger.setLevel(logging.ERROR)
56
+ return logger
57
+
58
+ # Library default: no stderr output; avoid interfering with calling scripts.
59
+ logger.addHandler(logging.NullHandler())
60
+ logger.propagate = False
61
+ if quiet:
62
+ logger.setLevel(logging.ERROR)
63
+ else:
64
+ env_level = os.getenv("AZURE_DISCOVERY_LOG_LEVEL", "INFO").upper()
65
+ logger.setLevel(env_level)
66
+ return logger
67
+
68
+
69
+ def enable_cli_logging(quiet: bool = False) -> None:
70
+ """Attach stderr + JSON handler so logs are emitted when run as the CLI.
71
+
72
+ Call this from the CLI entrypoint only. When used as a library, do not call
73
+ this so the package does not write to stderr.
74
+ """
75
+ logger = logging.getLogger(_LOGGER_NAME)
76
+ # Replace any existing handlers (e.g. NullHandler from get_logger) with our CLI handler.
77
+ logger.handlers.clear()
78
+ handler = logging.StreamHandler(sys.stderr)
79
+ handler.setFormatter(_build_json_formatter())
80
+ logger.addHandler(handler)
81
+ logger.propagate = False
82
+ if quiet:
83
+ logger.setLevel(logging.ERROR)
84
+ else:
85
+ env_level = os.getenv("AZURE_DISCOVERY_LOG_LEVEL", "INFO").upper()
86
+ logger.setLevel(env_level)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: azure-discovery
3
- Version: 0.1.0
3
+ Version: 0.1.2
4
4
  Summary: Lightweight Azure tenant discovery and visualization via Resource Graph. Enumerates subscriptions and resources, normalizes results, and renders interactive dependency graphs. Supports public and sovereign clouds (Gov, China, Germany, Azure Stack).
5
5
  Author: David Frazer <david.frazer336@gmail.com>
6
6
  License-Expression: MIT
@@ -1,116 +1,116 @@
1
- [build-system]
2
- requires = ["setuptools>=66", "wheel"]
3
- build-backend = "setuptools.build_meta"
4
-
5
- [project]
6
- name = "azure-discovery"
7
- version = "0.1.0"
8
- description = "Lightweight Azure tenant discovery and visualization via Resource Graph. Enumerates subscriptions and resources, normalizes results, and renders interactive dependency graphs. Supports public and sovereign clouds (Gov, China, Germany, Azure Stack)."
9
- readme = "README.md"
10
- license = "MIT"
11
- requires-python = ">=3.11"
12
- authors = [
13
- { name = "David Frazer <david.frazer336@gmail.com>" }
14
- ]
15
- keywords = [
16
- "azure",
17
- "resource-graph",
18
- "discovery",
19
- "inventory",
20
- "sovereign-cloud",
21
- "visualization",
22
- ]
23
- classifiers = [
24
- "Development Status :: 4 - Beta",
25
- "Intended Audience :: Developers",
26
- "Operating System :: OS Independent",
27
- "Programming Language :: Python :: 3",
28
- "Programming Language :: Python :: 3.11",
29
- "Programming Language :: Python :: 3.12",
30
- "Topic :: System :: Systems Administration",
31
- ]
32
- dependencies = [
33
- "pydantic>=2.7",
34
- "fastapi>=0.110",
35
- "uvicorn>=0.30",
36
- "typer>=0.12",
37
- "pyvis>=0.3.2",
38
- "azure-identity>=1.17",
39
- "azure-mgmt-resourcegraph>=8.0",
40
- "azure-mgmt-subscription>=3.1",
41
- ]
42
-
43
- [project.optional-dependencies]
44
- dev = [
45
- "pytest>=8.2",
46
- "pytest-asyncio>=0.23",
47
- "pytest-cov>=5.0",
48
- "ruff>=0.4.0",
49
- "mypy>=1.10",
50
- ]
51
-
52
- [project.scripts]
53
- azure-discovery = "azure_discovery.cli:main"
54
-
55
- [project.urls]
56
- Documentation = "https://github.com/maravedi/AzureDiscovery#readme"
57
- Repository = "https://github.com/maravedi/AzureDiscovery"
58
- "Bug Tracker" = "https://github.com/maravedi/AzureDiscovery/issues"
59
-
60
- [tool.setuptools.packages.find]
61
- where = ["."]
62
- include = ["azure_discovery*"]
63
-
64
- [tool.pytest.ini_options]
65
- asyncio_mode = "auto"
66
- testpaths = ["tests"]
67
- python_files = "test_*.py"
68
- python_functions = "test_*"
69
- addopts = "--cov=azure_discovery --cov-report=term-missing --cov-report=html"
70
-
71
- [tool.ruff]
72
- line-length = 100
73
- target-version = "py311"
74
-
75
- [tool.ruff.lint]
76
- select = [
77
- "E", # pycodestyle errors
78
- "W", # pycodestyle warnings
79
- "F", # pyflakes
80
- "I", # isort
81
- "B", # flake8-bugbear
82
- "C4", # flake8-comprehensions
83
- "UP", # pyupgrade
84
- ]
85
- ignore = [
86
- "E501", # line too long (handled by formatter)
87
- ]
88
-
89
- [tool.mypy]
90
- python_version = "3.11"
91
- strict = true
92
- warn_return_any = true
93
- warn_unused_configs = true
94
- disallow_untyped_defs = true
95
- disallow_any_generics = false
96
- disallow_subclassing_any = false
97
- warn_redundant_casts = true
98
- warn_unused_ignores = true
99
- no_implicit_optional = true
100
- check_untyped_defs = true
101
-
102
- [tool.coverage.run]
103
- omit = [
104
- "tests/*",
105
- "*/__init__.py",
106
- ]
107
-
108
- [tool.coverage.report]
109
- exclude_lines = [
110
- "pragma: no cover",
111
- "def __repr__",
112
- "raise AssertionError",
113
- "raise NotImplementedError",
114
- "if __name__ == .__main__.:",
115
- "if TYPE_CHECKING:",
116
- ]
1
+ [build-system]
2
+ requires = ["setuptools>=66", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "azure-discovery"
7
+ version = "0.1.2"
8
+ description = "Lightweight Azure tenant discovery and visualization via Resource Graph. Enumerates subscriptions and resources, normalizes results, and renders interactive dependency graphs. Supports public and sovereign clouds (Gov, China, Germany, Azure Stack)."
9
+ readme = "README.md"
10
+ license = "MIT"
11
+ requires-python = ">=3.11"
12
+ authors = [
13
+ { name = "David Frazer <david.frazer336@gmail.com>" }
14
+ ]
15
+ keywords = [
16
+ "azure",
17
+ "resource-graph",
18
+ "discovery",
19
+ "inventory",
20
+ "sovereign-cloud",
21
+ "visualization",
22
+ ]
23
+ classifiers = [
24
+ "Development Status :: 4 - Beta",
25
+ "Intended Audience :: Developers",
26
+ "Operating System :: OS Independent",
27
+ "Programming Language :: Python :: 3",
28
+ "Programming Language :: Python :: 3.11",
29
+ "Programming Language :: Python :: 3.12",
30
+ "Topic :: System :: Systems Administration",
31
+ ]
32
+ dependencies = [
33
+ "pydantic>=2.7",
34
+ "fastapi>=0.110",
35
+ "uvicorn>=0.30",
36
+ "typer>=0.12",
37
+ "pyvis>=0.3.2",
38
+ "azure-identity>=1.17",
39
+ "azure-mgmt-resourcegraph>=8.0",
40
+ "azure-mgmt-subscription>=3.1",
41
+ ]
42
+
43
+ [project.optional-dependencies]
44
+ dev = [
45
+ "pytest>=8.2",
46
+ "pytest-asyncio>=0.23",
47
+ "pytest-cov>=5.0",
48
+ "ruff>=0.4.0",
49
+ "mypy>=1.10",
50
+ ]
51
+
52
+ [project.scripts]
53
+ azure-discovery = "azure_discovery.cli:main"
54
+
55
+ [project.urls]
56
+ Documentation = "https://github.com/maravedi/AzureDiscovery#readme"
57
+ Repository = "https://github.com/maravedi/AzureDiscovery"
58
+ "Bug Tracker" = "https://github.com/maravedi/AzureDiscovery/issues"
59
+
60
+ [tool.setuptools.packages.find]
61
+ where = ["."]
62
+ include = ["azure_discovery*"]
63
+
64
+ [tool.pytest.ini_options]
65
+ asyncio_mode = "auto"
66
+ testpaths = ["tests"]
67
+ python_files = "test_*.py"
68
+ python_functions = "test_*"
69
+ addopts = "--cov=azure_discovery --cov-report=term-missing --cov-report=html"
70
+
71
+ [tool.ruff]
72
+ line-length = 100
73
+ target-version = "py311"
74
+
75
+ [tool.ruff.lint]
76
+ select = [
77
+ "E", # pycodestyle errors
78
+ "W", # pycodestyle warnings
79
+ "F", # pyflakes
80
+ "I", # isort
81
+ "B", # flake8-bugbear
82
+ "C4", # flake8-comprehensions
83
+ "UP", # pyupgrade
84
+ ]
85
+ ignore = [
86
+ "E501", # line too long (handled by formatter)
87
+ ]
88
+
89
+ [tool.mypy]
90
+ python_version = "3.11"
91
+ strict = true
92
+ warn_return_any = true
93
+ warn_unused_configs = true
94
+ disallow_untyped_defs = true
95
+ disallow_any_generics = false
96
+ disallow_subclassing_any = false
97
+ warn_redundant_casts = true
98
+ warn_unused_ignores = true
99
+ no_implicit_optional = true
100
+ check_untyped_defs = true
101
+
102
+ [tool.coverage.run]
103
+ omit = [
104
+ "tests/*",
105
+ "*/__init__.py",
106
+ ]
107
+
108
+ [tool.coverage.report]
109
+ exclude_lines = [
110
+ "pragma: no cover",
111
+ "def __repr__",
112
+ "raise AssertionError",
113
+ "raise NotImplementedError",
114
+ "if __name__ == .__main__.:",
115
+ "if TYPE_CHECKING:",
116
+ ]
@@ -1,59 +0,0 @@
1
- """Structured logging helpers."""
2
-
3
- from __future__ import annotations
4
-
5
- import json
6
- import logging
7
- import os
8
- import sys
9
- from typing import Any, Dict
10
-
11
- _LOGGER_NAME = "azure_discovery"
12
-
13
-
14
- def _build_json_formatter() -> logging.Formatter:
15
- class JsonFormatter(logging.Formatter):
16
- def format(self, record: logging.LogRecord) -> str:
17
- payload: Dict[str, Any] = {
18
- "logger": record.name,
19
- "level": record.levelname,
20
- "message": record.getMessage(),
21
- "module": record.module,
22
- "function": record.funcName,
23
- }
24
- if record.exc_info:
25
- payload["exc_info"] = self.formatException(record.exc_info)
26
- if record.__dict__.get("context"):
27
- payload["context"] = record.__dict__["context"]
28
- return json.dumps(payload)
29
-
30
- return JsonFormatter()
31
-
32
-
33
- def get_logger(quiet: bool = False) -> logging.Logger:
34
- """Return module-wide structured logger.
35
-
36
- Args:
37
- quiet: If True, only log ERROR and above. Logs always go to stderr.
38
- """
39
-
40
- logger = logging.getLogger(_LOGGER_NAME)
41
- if logger.handlers:
42
- # Update log level if quiet mode changed
43
- if quiet:
44
- logger.setLevel(logging.ERROR)
45
- return logger
46
-
47
- # Always use stderr for logs, never stdout
48
- handler = logging.StreamHandler(sys.stderr)
49
- handler.setFormatter(_build_json_formatter())
50
- logger.addHandler(handler)
51
-
52
- if quiet:
53
- logger.setLevel(logging.ERROR)
54
- else:
55
- env_level = os.getenv("AZURE_DISCOVERY_LOG_LEVEL", "INFO").upper()
56
- logger.setLevel(env_level)
57
-
58
- logger.propagate = False
59
- return logger
File without changes