arc-utils 1.1__tar.gz → 1.3__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.
- arc_utils-1.3/PKG-INFO +117 -0
- arc_utils-1.3/README.md +98 -0
- arc_utils-1.3/arc_utils/__init__.py +10 -0
- arc_utils-1.3/arc_utils/_inputs.py +105 -0
- {arc_utils-1.1 → arc_utils-1.3}/arc_utils/aprx.py +12 -4
- {arc_utils-1.1 → arc_utils-1.3}/arc_utils/gdb.py +58 -14
- arc_utils-1.3/arc_utils/output.py +111 -0
- {arc_utils-1.1 → arc_utils-1.3}/arc_utils/table.py +178 -95
- arc_utils-1.3/arc_utils.egg-info/PKG-INFO +117 -0
- {arc_utils-1.1 → arc_utils-1.3}/arc_utils.egg-info/SOURCES.txt +3 -2
- {arc_utils-1.1 → arc_utils-1.3}/arc_utils.egg-info/top_level.txt +2 -0
- arc_utils-1.3/examples/extract-featureclass-details.py +124 -0
- arc_utils-1.3/pyproject.toml +32 -0
- {arc_utils-1.1 → arc_utils-1.3}/setup.cfg +1 -1
- arc_utils-1.3/setup.py +3 -0
- {arc_utils-1.1 → arc_utils-1.3}/tests/conftest.py +1 -6
- {arc_utils-1.1 → arc_utils-1.3}/tests/test_aprx.py +12 -0
- arc_utils-1.3/tests/test_gdb.py +27 -0
- arc_utils-1.3/tests/test_table.py +129 -0
- arc_utils-1.1/PKG-INFO +0 -70
- arc_utils-1.1/README.md +0 -49
- arc_utils-1.1/arc_utils/__init__.py +0 -16
- arc_utils-1.1/arc_utils/mxd.py +0 -46
- arc_utils-1.1/arc_utils/output.py +0 -80
- arc_utils-1.1/arc_utils.egg-info/PKG-INFO +0 -70
- arc_utils-1.1/setup.py +0 -41
- arc_utils-1.1/tests/test_gdb.py +0 -14
- arc_utils-1.1/tests/test_mxd.py +0 -13
- arc_utils-1.1/tests/test_table.py +0 -69
- {arc_utils-1.1 → arc_utils-1.3}/LICENSE.txt +0 -0
- {arc_utils-1.1 → arc_utils-1.3}/arc_utils.egg-info/dependency_links.txt +0 -0
- {arc_utils-1.1 → arc_utils-1.3}/tests/__init__.py +0 -0
arc_utils-1.3/PKG-INFO
ADDED
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: arc-utils
|
|
3
|
+
Version: 1.3
|
|
4
|
+
Summary: Python utilities for use with Esri ArcGIS Pro software
|
|
5
|
+
Author-email: Grant Herbert <gdherbert@gmail.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/gdherbert/arc_utils
|
|
8
|
+
Project-URL: Download, https://github.com/gdherbert/arc_utils/tree/1.3
|
|
9
|
+
Keywords: esri,arcpy,arcgis
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: Programming Language :: Python
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
15
|
+
Requires-Python: >=3.11
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
License-File: LICENSE.txt
|
|
18
|
+
Dynamic: license-file
|
|
19
|
+
|
|
20
|
+
# README #
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### What is this repository for? ###
|
|
24
|
+
* A collection of (mostly) arcpy related utilities for use within ArcGIS Pro (Python 3).
|
|
25
|
+
Shortcuts for accessing elements of a map document, performing various data discovery tasks on a table or geodatabase
|
|
26
|
+
|
|
27
|
+
### How do I get set up? ###
|
|
28
|
+
|
|
29
|
+
Install from PyPI:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install arc-utils
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
For local development and editable usage from clone:
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
python -m pip install -e .
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
To use the utilities:
|
|
42
|
+
|
|
43
|
+
* in the python window in ArcGIS Pro
|
|
44
|
+
|
|
45
|
+
``import arc_utils as au``
|
|
46
|
+
|
|
47
|
+
* typing ``au.`` will now reveal the modules and functions available to you if you have autocomplete on
|
|
48
|
+
|
|
49
|
+
* Depends on arcpy (only available with Esri license)
|
|
50
|
+
|
|
51
|
+
### Example usage ###
|
|
52
|
+
|
|
53
|
+
``import arc_utils as au``
|
|
54
|
+
|
|
55
|
+
``tbl = au.table.TableObj(path to featureclass)``
|
|
56
|
+
|
|
57
|
+
# list all fields
|
|
58
|
+
|
|
59
|
+
``print(tbl.fields)``
|
|
60
|
+
|
|
61
|
+
``pro_doc = au.aprx.AprxObj(“CURRENT”)``
|
|
62
|
+
|
|
63
|
+
``pro_doc.maps`` >> [<arcpy._mp.Map object at 0x000001A4AECBF108>, <arcpy._mp.Map object at 0x000001A4AEBB6608>]
|
|
64
|
+
|
|
65
|
+
``pro_doc.maps[0].name`` >> ‘Map’
|
|
66
|
+
|
|
67
|
+
### Accepted Input Types ###
|
|
68
|
+
|
|
69
|
+
Most path parameters now accept:
|
|
70
|
+
|
|
71
|
+
* string path
|
|
72
|
+
* ``pathlib.Path`` / other path-like objects
|
|
73
|
+
* wrapper objects with ``.path``
|
|
74
|
+
* ArcGIS layer/table objects with ``.catalogPath`` or ``.dataSource`` (where applicable)
|
|
75
|
+
|
|
76
|
+
Invalid paths raise ``ValueError("invalid path")``.
|
|
77
|
+
|
|
78
|
+
Constructor acceptance is preserved (for example, passing path-like and wrapper objects directly to ``TableObj``, ``GDBObj``, and ``AprxObj``).
|
|
79
|
+
|
|
80
|
+
### Exporting field values to Excel ###
|
|
81
|
+
|
|
82
|
+
```python
|
|
83
|
+
import arc_utils as au
|
|
84
|
+
from openpyxl import Workbook
|
|
85
|
+
|
|
86
|
+
# Single table export with class method
|
|
87
|
+
tbl = au.table.TableObj(r"C:\path\to\featureclass")
|
|
88
|
+
wb = Workbook()
|
|
89
|
+
ws = wb.active
|
|
90
|
+
tbl.export_fields_to_worksheet(ws)
|
|
91
|
+
wb.save(r"C:\path\to\schema_values.xlsx")
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
```python
|
|
95
|
+
# Multi-layer export with module function
|
|
96
|
+
layers = [r"C:\path\to\layer1", r"C:\path\to\layer2"]
|
|
97
|
+
au.table.export_field_sets(layers, r"C:\path\to\all_layers.xlsx")
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
# Worksheet naming behavior:
|
|
102
|
+
# use_lyr_alias=True -> prefer alias/name (human-readable)
|
|
103
|
+
# use_lyr_alias=False -> use full table path (traceable)
|
|
104
|
+
au.table.export_field_sets(layers, r"C:\path\to\all_layers.xlsx", use_lyr_alias=True)
|
|
105
|
+
au.table.export_field_sets(layers, r"C:\path\to\all_layers_by_path.xlsx", use_lyr_alias=False)
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
```python
|
|
109
|
+
# Duplicate detection outputs
|
|
110
|
+
tbl = au.table.TableObj(r"C:\path\to\featureclass")
|
|
111
|
+
dup_values = tbl.find_duplicate_field_values("STATUS", output="set")
|
|
112
|
+
dup_rows_df = tbl.find_duplicate_field_values(["STATUS", "TYPE"], output="df")
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
### Contribution guidelines ###
|
|
116
|
+
|
|
117
|
+
Contributions welcomed, this is a starting point for various utilities that I think could be useful within ArcGIS Pro.
|
arc_utils-1.3/README.md
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# README #
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### What is this repository for? ###
|
|
5
|
+
* A collection of (mostly) arcpy related utilities for use within ArcGIS Pro (Python 3).
|
|
6
|
+
Shortcuts for accessing elements of a map document, performing various data discovery tasks on a table or geodatabase
|
|
7
|
+
|
|
8
|
+
### How do I get set up? ###
|
|
9
|
+
|
|
10
|
+
Install from PyPI:
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
pip install arc-utils
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
For local development and editable usage from clone:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
python -m pip install -e .
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
To use the utilities:
|
|
23
|
+
|
|
24
|
+
* in the python window in ArcGIS Pro
|
|
25
|
+
|
|
26
|
+
``import arc_utils as au``
|
|
27
|
+
|
|
28
|
+
* typing ``au.`` will now reveal the modules and functions available to you if you have autocomplete on
|
|
29
|
+
|
|
30
|
+
* Depends on arcpy (only available with Esri license)
|
|
31
|
+
|
|
32
|
+
### Example usage ###
|
|
33
|
+
|
|
34
|
+
``import arc_utils as au``
|
|
35
|
+
|
|
36
|
+
``tbl = au.table.TableObj(path to featureclass)``
|
|
37
|
+
|
|
38
|
+
# list all fields
|
|
39
|
+
|
|
40
|
+
``print(tbl.fields)``
|
|
41
|
+
|
|
42
|
+
``pro_doc = au.aprx.AprxObj(“CURRENT”)``
|
|
43
|
+
|
|
44
|
+
``pro_doc.maps`` >> [<arcpy._mp.Map object at 0x000001A4AECBF108>, <arcpy._mp.Map object at 0x000001A4AEBB6608>]
|
|
45
|
+
|
|
46
|
+
``pro_doc.maps[0].name`` >> ‘Map’
|
|
47
|
+
|
|
48
|
+
### Accepted Input Types ###
|
|
49
|
+
|
|
50
|
+
Most path parameters now accept:
|
|
51
|
+
|
|
52
|
+
* string path
|
|
53
|
+
* ``pathlib.Path`` / other path-like objects
|
|
54
|
+
* wrapper objects with ``.path``
|
|
55
|
+
* ArcGIS layer/table objects with ``.catalogPath`` or ``.dataSource`` (where applicable)
|
|
56
|
+
|
|
57
|
+
Invalid paths raise ``ValueError("invalid path")``.
|
|
58
|
+
|
|
59
|
+
Constructor acceptance is preserved (for example, passing path-like and wrapper objects directly to ``TableObj``, ``GDBObj``, and ``AprxObj``).
|
|
60
|
+
|
|
61
|
+
### Exporting field values to Excel ###
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
import arc_utils as au
|
|
65
|
+
from openpyxl import Workbook
|
|
66
|
+
|
|
67
|
+
# Single table export with class method
|
|
68
|
+
tbl = au.table.TableObj(r"C:\path\to\featureclass")
|
|
69
|
+
wb = Workbook()
|
|
70
|
+
ws = wb.active
|
|
71
|
+
tbl.export_fields_to_worksheet(ws)
|
|
72
|
+
wb.save(r"C:\path\to\schema_values.xlsx")
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
# Multi-layer export with module function
|
|
77
|
+
layers = [r"C:\path\to\layer1", r"C:\path\to\layer2"]
|
|
78
|
+
au.table.export_field_sets(layers, r"C:\path\to\all_layers.xlsx")
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
# Worksheet naming behavior:
|
|
83
|
+
# use_lyr_alias=True -> prefer alias/name (human-readable)
|
|
84
|
+
# use_lyr_alias=False -> use full table path (traceable)
|
|
85
|
+
au.table.export_field_sets(layers, r"C:\path\to\all_layers.xlsx", use_lyr_alias=True)
|
|
86
|
+
au.table.export_field_sets(layers, r"C:\path\to\all_layers_by_path.xlsx", use_lyr_alias=False)
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
```python
|
|
90
|
+
# Duplicate detection outputs
|
|
91
|
+
tbl = au.table.TableObj(r"C:\path\to\featureclass")
|
|
92
|
+
dup_values = tbl.find_duplicate_field_values("STATUS", output="set")
|
|
93
|
+
dup_rows_df = tbl.find_duplicate_field_values(["STATUS", "TYPE"], output="df")
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Contribution guidelines ###
|
|
97
|
+
|
|
98
|
+
Contributions welcomed, this is a starting point for various utilities that I think could be useful within ArcGIS Pro.
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""Shared input coercion helpers for arc_utils."""
|
|
3
|
+
import os
|
|
4
|
+
import arcpy
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def _normalize_to_sequence(values):
|
|
8
|
+
"""Return a list from single or multi-value inputs.
|
|
9
|
+
|
|
10
|
+
Strings and path-like values are treated as a single item.
|
|
11
|
+
"""
|
|
12
|
+
if isinstance(values, (list, tuple, set)):
|
|
13
|
+
return list(values)
|
|
14
|
+
return [values]
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def _to_path_str(value):
|
|
18
|
+
"""Convert path-like values to str where possible."""
|
|
19
|
+
if value is None:
|
|
20
|
+
return None
|
|
21
|
+
try:
|
|
22
|
+
value = os.fspath(value)
|
|
23
|
+
except TypeError:
|
|
24
|
+
return None
|
|
25
|
+
if isinstance(value, bytes):
|
|
26
|
+
value = value.decode()
|
|
27
|
+
return value
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def _resolve_dataset_path(value, arg_name="value"):
|
|
31
|
+
"""Resolve supported dataset inputs to a path string.
|
|
32
|
+
|
|
33
|
+
Supported inputs:
|
|
34
|
+
- str and pathlib.Path / os.PathLike
|
|
35
|
+
- ArcGIS Pro layer-name strings (resolved via arcpy.Describe(...).catalogPath)
|
|
36
|
+
- objects exposing .path (wrapper objects)
|
|
37
|
+
- ArcGIS Pro map/layer objects exposing .catalogPath or .dataSource
|
|
38
|
+
"""
|
|
39
|
+
def _resolve_candidate(candidate):
|
|
40
|
+
"""Resolve map layer names and object references to catalog paths."""
|
|
41
|
+
try:
|
|
42
|
+
desc = arcpy.Describe(candidate)
|
|
43
|
+
if hasattr(desc, "catalogPath") and desc.catalogPath:
|
|
44
|
+
return os.path.abspath(desc.catalogPath)
|
|
45
|
+
except Exception:
|
|
46
|
+
pass
|
|
47
|
+
return os.path.abspath(candidate)
|
|
48
|
+
|
|
49
|
+
for attr in ("path", "catalogPath", "dataSource"):
|
|
50
|
+
if hasattr(value, attr):
|
|
51
|
+
candidate = _to_path_str(getattr(value, attr))
|
|
52
|
+
if candidate:
|
|
53
|
+
return _resolve_candidate(candidate)
|
|
54
|
+
|
|
55
|
+
direct = _to_path_str(value)
|
|
56
|
+
if direct:
|
|
57
|
+
return _resolve_candidate(direct)
|
|
58
|
+
|
|
59
|
+
raise TypeError("{} must be a path-like string or object with a valid path".format(arg_name))
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _resolve_aprx_path(value, arg_name="value"):
|
|
63
|
+
"""Resolve Aprx path input, preserving CURRENT special value."""
|
|
64
|
+
direct = _to_path_str(value)
|
|
65
|
+
if isinstance(direct, str) and direct.upper() == "CURRENT":
|
|
66
|
+
return "CURRENT"
|
|
67
|
+
|
|
68
|
+
for attr in ("path", "catalogPath", "dataSource"):
|
|
69
|
+
if hasattr(value, attr):
|
|
70
|
+
candidate = _to_path_str(getattr(value, attr))
|
|
71
|
+
if isinstance(candidate, str) and candidate.upper() == "CURRENT":
|
|
72
|
+
return "CURRENT"
|
|
73
|
+
if candidate:
|
|
74
|
+
return os.path.abspath(candidate)
|
|
75
|
+
|
|
76
|
+
if direct:
|
|
77
|
+
return os.path.abspath(direct)
|
|
78
|
+
|
|
79
|
+
raise TypeError("{} must be a path-like string or object with a valid path".format(arg_name))
|
|
80
|
+
|
|
81
|
+
|
|
82
|
+
def _ensure_valid_path(path):
|
|
83
|
+
"""Validate ArcGIS path-like input and raise a consistent error."""
|
|
84
|
+
if not arcpy.Exists(path):
|
|
85
|
+
raise ValueError("invalid path")
|
|
86
|
+
return path
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def _input_display_name(value, default_name=None):
|
|
90
|
+
"""Best-effort human-readable name for logs and worksheet names."""
|
|
91
|
+
for attr in ("name",):
|
|
92
|
+
if hasattr(value, attr):
|
|
93
|
+
candidate = getattr(value, attr)
|
|
94
|
+
if candidate:
|
|
95
|
+
return str(candidate)
|
|
96
|
+
|
|
97
|
+
for attr in ("path", "catalogPath", "dataSource"):
|
|
98
|
+
if hasattr(value, attr):
|
|
99
|
+
candidate = getattr(value, attr)
|
|
100
|
+
if candidate:
|
|
101
|
+
return str(candidate)
|
|
102
|
+
|
|
103
|
+
if default_name is not None:
|
|
104
|
+
return str(default_name)
|
|
105
|
+
return str(value)
|
|
@@ -3,20 +3,28 @@
|
|
|
3
3
|
"""
|
|
4
4
|
|
|
5
5
|
import arcpy
|
|
6
|
+
import os
|
|
7
|
+
from ._inputs import _resolve_aprx_path
|
|
6
8
|
|
|
7
9
|
class AprxObj(object):
|
|
8
10
|
""" provide methods for working with a ArcGIS Pro aprx file
|
|
9
11
|
all standard arcpy methods are available via .aprx
|
|
10
12
|
Usage: pro_doc = arc_utils.aprx.AprxObj(path)
|
|
11
13
|
:param
|
|
12
|
-
path:
|
|
13
|
-
|
|
14
|
+
path: aprx input accepted as
|
|
15
|
+
- string path
|
|
16
|
+
- pathlib.Path / os.PathLike
|
|
17
|
+
- wrapper object exposing .path
|
|
18
|
+
- "CURRENT" if used in ArcGIS Pro Python window
|
|
19
|
+
invalid paths raise ValueError("invalid path")
|
|
14
20
|
"""
|
|
15
21
|
def __init__(self, aprx_path):
|
|
16
22
|
""" :param path to aprx or "CURRENT"
|
|
17
23
|
"""
|
|
18
|
-
self.
|
|
19
|
-
self.path
|
|
24
|
+
self.path = _resolve_aprx_path(aprx_path, arg_name="aprx_path")
|
|
25
|
+
if self.path != "CURRENT" and not os.path.exists(self.path):
|
|
26
|
+
raise ValueError("invalid path")
|
|
27
|
+
self.aprx = arcpy.mp.ArcGISProject(self.path)
|
|
20
28
|
self.maps = self.get_maps()
|
|
21
29
|
self.layouts = self.get_layouts()
|
|
22
30
|
|
|
@@ -1,31 +1,38 @@
|
|
|
1
1
|
# -*- coding: utf-8 -*-
|
|
2
2
|
"""utilities for working with geodatabases and reporting on geodatabase contents
|
|
3
3
|
"""
|
|
4
|
-
from __future__ import print_function, unicode_literals, absolute_import
|
|
5
4
|
import os
|
|
6
5
|
import arcpy
|
|
7
6
|
from .output import get_valid_output_path
|
|
8
7
|
from .output import output_msg
|
|
8
|
+
from ._inputs import _ensure_valid_path
|
|
9
|
+
from ._inputs import _normalize_to_sequence
|
|
10
|
+
from ._inputs import _resolve_dataset_path
|
|
9
11
|
|
|
10
12
|
class GDBObj(object):
|
|
11
13
|
""" provide properties for working with a GDB
|
|
12
14
|
Usage: gdb = arc_utils.gdb.GDBObj(path)
|
|
13
15
|
:param
|
|
14
|
-
path:
|
|
16
|
+
path: geodatabase input accepted as
|
|
17
|
+
- string path
|
|
18
|
+
- pathlib.Path / os.PathLike
|
|
19
|
+
- wrapper object exposing .path
|
|
20
|
+
- ArcGIS object exposing .catalogPath or .dataSource
|
|
15
21
|
"""
|
|
16
22
|
def __init__(self, gdb_path):
|
|
17
23
|
""" sets up reference to table
|
|
18
24
|
adds properties and methods
|
|
19
25
|
"""
|
|
20
|
-
self.path = gdb_path
|
|
26
|
+
self.path = _ensure_valid_path(_resolve_dataset_path(gdb_path, arg_name="gdb_path"))
|
|
21
27
|
self.describe_obj = self._describe_object()
|
|
22
28
|
self.feature_classes = self.get_feature_class_names()
|
|
29
|
+
self.tables = self.get_table_names()
|
|
23
30
|
self.domain_names = self.get_all_domain_names()
|
|
24
31
|
|
|
25
32
|
def _describe_object(self):
|
|
26
33
|
""" returns describe object"""
|
|
27
34
|
return arcpy.Describe(self.path)
|
|
28
|
-
|
|
35
|
+
|
|
29
36
|
def get_feature_class_names(self):
|
|
30
37
|
""" get a list of all the featureclass names"""
|
|
31
38
|
fc_list = []
|
|
@@ -38,6 +45,17 @@ class GDBObj(object):
|
|
|
38
45
|
fc_list.append(fc)
|
|
39
46
|
arcpy.env.workspace = temp_ws
|
|
40
47
|
return fc_list
|
|
48
|
+
|
|
49
|
+
def get_table_names(self):
|
|
50
|
+
""" get a list of all the table names"""
|
|
51
|
+
tbl_list = []
|
|
52
|
+
temp_ws = arcpy.env.workspace
|
|
53
|
+
arcpy.env.workspace = self.path
|
|
54
|
+
tbls = arcpy.ListTables()
|
|
55
|
+
for tbl in tbls:
|
|
56
|
+
tbl_list.append(tbl)
|
|
57
|
+
arcpy.env.workspace = temp_ws
|
|
58
|
+
return tbl_list
|
|
41
59
|
|
|
42
60
|
def get_all_domain_names(self):
|
|
43
61
|
domain_names = []
|
|
@@ -46,14 +64,27 @@ class GDBObj(object):
|
|
|
46
64
|
domain_names.append(domain.name)
|
|
47
65
|
return domain_names
|
|
48
66
|
|
|
67
|
+
def OID_check(self):
|
|
68
|
+
for fc in self.feature_classes:
|
|
69
|
+
oidfield = ''
|
|
70
|
+
tmp = arcpy.Describe(fc)
|
|
71
|
+
if tmp.hasOID:
|
|
72
|
+
oidfield = tmp.OIDFieldName
|
|
73
|
+
print('featureclass', tmp.name, tmp.hasOID, oidfield)
|
|
74
|
+
for tb in self.tables:
|
|
75
|
+
oidfield = ''
|
|
76
|
+
tmp = arcpy.Describe(tb)
|
|
77
|
+
if tmp.hasOID:
|
|
78
|
+
oidfield = tmp.OIDFieldName
|
|
79
|
+
print('table', tmp.name, tmp.hasOID, oidfield)
|
|
49
80
|
|
|
50
81
|
#TODO split into 3 - get all FC, create formatted string output, write to file. use io
|
|
51
82
|
def report_all_fc_as_text(geodatabase, output_file=None, sep='\t'):
|
|
52
83
|
"""Create a text report of all fields in all featureclasses/tables from a geodatabase
|
|
53
84
|
to specified output file.
|
|
54
85
|
|
|
55
|
-
:param geodatabase {String}
|
|
56
|
-
|
|
86
|
+
:param geodatabase {String|pathlike|object}
|
|
87
|
+
Geodatabase path or object reference.
|
|
57
88
|
|
|
58
89
|
:param output_file {String}
|
|
59
90
|
Path or reference to a text file. If not supplied defaults to gdb directory.
|
|
@@ -63,10 +94,13 @@ def report_all_fc_as_text(geodatabase, output_file=None, sep='\t'):
|
|
|
63
94
|
"""
|
|
64
95
|
default_env = arcpy.env.workspace
|
|
65
96
|
try:
|
|
97
|
+
geodatabase = _ensure_valid_path(_resolve_dataset_path(geodatabase, arg_name="geodatabase"))
|
|
66
98
|
desc = arcpy.Describe(geodatabase)
|
|
67
99
|
arcpy.env.workspace = geodatabase
|
|
68
100
|
if not output_file:
|
|
69
101
|
path = get_valid_output_path(desc.Path)
|
|
102
|
+
if not path:
|
|
103
|
+
raise ValueError("invalid output path")
|
|
70
104
|
output_file = os.path.join(path, desc.name.split(".")[0] + ".txt")
|
|
71
105
|
|
|
72
106
|
output_msg("Writing to: {0}".format(output_file))
|
|
@@ -99,7 +133,7 @@ def report_all_fc_as_text(geodatabase, output_file=None, sep='\t'):
|
|
|
99
133
|
|
|
100
134
|
for dataset in datasets:
|
|
101
135
|
for fc in arcpy.ListFeatureClasses(feature_dataset=dataset):
|
|
102
|
-
output_msg("Processing Dataset: {0}
|
|
136
|
+
output_msg("Processing Dataset: {0} \\ FeatureClass: {1}".format(dataset, fc))
|
|
103
137
|
try:
|
|
104
138
|
fields = arcpy.ListFields(fc)
|
|
105
139
|
str_output = ""
|
|
@@ -126,15 +160,18 @@ def export_all_domains(geodatabase, workspace=None):
|
|
|
126
160
|
"""Output all the domains in a geodatabase
|
|
127
161
|
to tables in a workspace.
|
|
128
162
|
|
|
129
|
-
:param geodatabase {String}:
|
|
163
|
+
:param geodatabase {String|pathlike|object}:
|
|
130
164
|
Path or reference to input geodatabase.
|
|
131
165
|
|
|
132
|
-
:param workspace {String}: Optional
|
|
166
|
+
:param workspace {String|pathlike|object}: Optional
|
|
133
167
|
Path to output folder or geodatabase. Defaults to input geodatabase.
|
|
134
168
|
"""
|
|
135
169
|
try:
|
|
170
|
+
geodatabase = _ensure_valid_path(_resolve_dataset_path(geodatabase, arg_name="geodatabase"))
|
|
136
171
|
if not workspace:
|
|
137
172
|
workspace = geodatabase
|
|
173
|
+
else:
|
|
174
|
+
workspace = _resolve_dataset_path(workspace, arg_name="workspace")
|
|
138
175
|
domains = arcpy.da.ListDomains(geodatabase)
|
|
139
176
|
for domain in domains:
|
|
140
177
|
dname = arcpy.ValidateTableName(domain.name + '_domain', workspace)
|
|
@@ -154,13 +191,20 @@ def export_all_domains(geodatabase, workspace=None):
|
|
|
154
191
|
def import_tables_as_domains(tables, geodatabase):
|
|
155
192
|
"""import tables as domains into geodatabase. Expects fields 'codedValues' and 'description'
|
|
156
193
|
|
|
157
|
-
:param tables {string}
|
|
158
|
-
path or array of paths
|
|
194
|
+
:param tables {string|pathlike|object|array}
|
|
195
|
+
table path/object or array of table paths/objects containing domain data
|
|
159
196
|
|
|
160
|
-
:param geodatabase
|
|
161
|
-
Path or reference to geodatabase.
|
|
197
|
+
:param geodatabase {String|pathlike|object}
|
|
198
|
+
Path or reference to geodatabase.
|
|
199
|
+
|
|
200
|
+
Notes:
|
|
201
|
+
Single string inputs are treated as a single table path (not iterated per character).
|
|
202
|
+
Invalid paths raise ValueError("invalid path").
|
|
203
|
+
"""
|
|
162
204
|
try:
|
|
163
|
-
|
|
205
|
+
geodatabase = _ensure_valid_path(_resolve_dataset_path(geodatabase, arg_name="geodatabase"))
|
|
206
|
+
for table in _normalize_to_sequence(tables):
|
|
207
|
+
table = _ensure_valid_path(_resolve_dataset_path(table, arg_name="tables"))
|
|
164
208
|
desc = arcpy.Describe(table)
|
|
165
209
|
dname = desc.name.replace("_domain", "")
|
|
166
210
|
arcpy.TableToDomain_management(table, "codedValues", "description", geodatabase, dname)
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
"""output related utilities
|
|
3
|
+
"""
|
|
4
|
+
import arcpy
|
|
5
|
+
import os
|
|
6
|
+
|
|
7
|
+
def output_msg(msg, severity=0):
|
|
8
|
+
"""Output msg to print and/or to Arc. Useful to include in a tool
|
|
9
|
+
that can be run in Python or in ArcGIS
|
|
10
|
+
|
|
11
|
+
msg{String}:
|
|
12
|
+
message to output.
|
|
13
|
+
|
|
14
|
+
severity(integer):
|
|
15
|
+
severity = 0 (none), 1 (warning), 2 (error)
|
|
16
|
+
usage:
|
|
17
|
+
output_msg("message")
|
|
18
|
+
|
|
19
|
+
function from http://help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#//00150000000p000000.htm
|
|
20
|
+
"""
|
|
21
|
+
|
|
22
|
+
# Adds a Message (in case this is run as a tool)
|
|
23
|
+
# and also prints the message to the screen (standard output)
|
|
24
|
+
#
|
|
25
|
+
print(msg)
|
|
26
|
+
|
|
27
|
+
# Split the message on \n first, so that if it's multiple lines,
|
|
28
|
+
# a GPMessage will be added for each line
|
|
29
|
+
try:
|
|
30
|
+
for string in msg.split('\n'):
|
|
31
|
+
# Add appropriate geoprocessing message
|
|
32
|
+
#
|
|
33
|
+
if severity == 0:
|
|
34
|
+
arcpy.AddMessage(string)
|
|
35
|
+
elif severity == 1:
|
|
36
|
+
arcpy.AddWarning(string)
|
|
37
|
+
elif severity == 2:
|
|
38
|
+
arcpy.AddError(string)
|
|
39
|
+
except:
|
|
40
|
+
pass
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
def get_valid_output_path(path, return_folder_only=True, make_dir=True, fallback_to_user_folder=True):
|
|
44
|
+
""" return a valid path or empty string if not valid.
|
|
45
|
+
If return_folder_only is True (default) and a gdb is passed as path,
|
|
46
|
+
will return the folder containing gdb.
|
|
47
|
+
If make_dir is True (default), path will be created if it doesn't exist..
|
|
48
|
+
If fallback_to_user_folder is True (default), will fallback to userprofile\documents folder
|
|
49
|
+
path {String}:
|
|
50
|
+
filepath
|
|
51
|
+
return_folder_only {Boolean}:
|
|
52
|
+
returned path must be a folder, not a .gdb
|
|
53
|
+
make_dir {Boolean}:
|
|
54
|
+
make the directory if not exists
|
|
55
|
+
fallback_to_user_folder {Boolean}:
|
|
56
|
+
if path not valid, fallback to userprofile\documents folder (if available)
|
|
57
|
+
:return path or empty string
|
|
58
|
+
"""
|
|
59
|
+
def _fallback_user_folder():
|
|
60
|
+
if not fallback_to_user_folder:
|
|
61
|
+
return ''
|
|
62
|
+
user_profile = os.environ.get('USERPROFILE') or os.path.expanduser('~')
|
|
63
|
+
if not user_profile:
|
|
64
|
+
return ''
|
|
65
|
+
docs_dir = os.path.join(user_profile, 'Documents')
|
|
66
|
+
if os.path.isdir(docs_dir):
|
|
67
|
+
return docs_dir
|
|
68
|
+
if os.path.isdir(user_profile):
|
|
69
|
+
return user_profile
|
|
70
|
+
return ''
|
|
71
|
+
|
|
72
|
+
try:
|
|
73
|
+
path = os.fspath(path)
|
|
74
|
+
except (TypeError, ValueError):
|
|
75
|
+
return _fallback_user_folder()
|
|
76
|
+
|
|
77
|
+
if not path:
|
|
78
|
+
return _fallback_user_folder()
|
|
79
|
+
|
|
80
|
+
path = os.path.abspath(os.path.expanduser(path))
|
|
81
|
+
report_dir = path
|
|
82
|
+
|
|
83
|
+
if os.path.isdir(path):
|
|
84
|
+
if return_folder_only and path.lower().endswith('.gdb'):
|
|
85
|
+
try:
|
|
86
|
+
report_dir = arcpy.Describe(path).Path
|
|
87
|
+
except Exception:
|
|
88
|
+
return _fallback_user_folder()
|
|
89
|
+
elif make_dir:
|
|
90
|
+
try:
|
|
91
|
+
os.makedirs(path)
|
|
92
|
+
report_dir = path
|
|
93
|
+
except OSError:
|
|
94
|
+
return _fallback_user_folder()
|
|
95
|
+
else:
|
|
96
|
+
return _fallback_user_folder()
|
|
97
|
+
|
|
98
|
+
if not os.path.isdir(report_dir):
|
|
99
|
+
return _fallback_user_folder()
|
|
100
|
+
|
|
101
|
+
return report_dir
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def output_to_file(data, path, filename):
|
|
105
|
+
"""send result string to file"""
|
|
106
|
+
path = get_valid_output_path(path)
|
|
107
|
+
if not path:
|
|
108
|
+
raise ValueError("invalid output path")
|
|
109
|
+
output_file = os.path.join(path, filename)
|
|
110
|
+
with open(output_file, "w") as output:
|
|
111
|
+
output.write('{}'.format(data))
|