ArcGIS API for Python - Get layer name and dataset?

11-07-2019 01:10 PM
by Anonymous User
Not applicable

I have two jupyter workspaces - one lists out all datasets associated with each service on our server (service manifest) and another that lists all layers associated with a feature layer.

What I have not been able to do is get both - i.e., the layer name (or title) as it appears in the service and the data source associated with that layer name. The procedures for getting each type of information are different.The service manifest does not have layer names, just a collection of datasets and the functions that list layer names do not list data sources.

This may get complicated, but if anyone knows how to get BOTH, and can just provide a hint or two of how this can be accomplished, it would be very much appreciated. I just don't know how layer name and data source (i.e., the name of the sde feature class being referenced) can both be captured together.

A report that lists both would be extremely useful for us, so we can track what datasource is feeding which layer and update it quickly when necessary.

Thank you,

Randy McGregor

0 Kudos
1 Reply
New Contributor II

Here's what I developed to get all the service datasets and store in SQL Server so they can be easily queried. Sorry it's a bit long but it should help point you in the right direction. Bottom line, there's no way to get layer name and data source with a single API call.

import json
import logging
import requests
import urllib
import pypyodbc
import utility

logger = logging.getLogger('ServiceCataloger')

with open('config.json', 'r') as f:
    main_config = json.load(f)

with open('update_service_catalog.json', 'r') as f:
    script_config = json.load(f)

class ServiceRecord(object):

    def __init__(self, database, dataset, service_name, service_type, service_url):
        self.database = database
        self.dataset = dataset
        self.service_name = service_name
        self.service_type = service_type
        self.service_url = service_url

    def as_tuple(self):

        return (self.database,

class ServiceCataloger(object):
    """Updates SQL Server table of services and associated feature class locks."""

    def __init__(self, admin_services_root):
        self.admin_services_root = admin_services_root
        self.manifest_path = 'iteminfo/manifest/manifest.json'
        self.service_types = ['FeatureServer', 'MapServer']
        self.skip_folders = ['System']
        self.skip_names = ['raster_data']
        self.server_config = main_config['authentication']['cws_ags']
        self.certificate = self.server_config['certificate']
        self.token_url = self.server_config['token_url']
        self.token_user = self.server_config['user']
        self.token_password = self.server_config['password']
        self.token = utility.get_token(self.token_url, self.token_user, self.token_password)
        self.session = requests.session()
        self.session.verify = self.certificate if self.certificate is not None else False

    def __del__(self):


    def __get_database_connection(self, database_name):
        """Return pypyodbc connection to named database (configured in config.json)."""

        db_config = script_config['database'][database_name.lower()]
        connection = pypyodbc.connect(
            r'DRIVER={SQL Server};'
            r'SERVER='      + db_config['server']   + ';'
            r'DATABASE='    + db_config['database'] + ';'
            r'UID='         + db_config['username'] + ';'
            r'PWD='         + db_config['password'])

        return connection

    def __make_request(self, request_url):

        return self.session.get(url=request_url, params={'f': 'json', 'token': self.token}).json()

    def __build_service_records(self, catalog_url):

        service_records = []
        catalog = self.__make_request(catalog_url)
        services = catalog['services']

        for service in services:

            svc_type = service['type']

            if svc_type in self.service_types:
                svc_name = service['serviceName']
                svc_url = urllib.parse.urljoin(catalog_url + '/', service['serviceName'] + '.' + service['type'])
                svc_manifest_url = urllib.parse.urljoin(svc_url + '/', self.manifest_path)
                svc_manifest = self.__make_request(svc_manifest_url)
                if svc_manifest.get('status') == 'error':
                    logger.warning("Manifest unavailable for service: {0}".format(svc_name))
                svc_databases = svc_manifest['databases']

                for database in svc_databases:
                    conn_string = database['onPremiseConnectionString']
                    conn_data = utility.parse_connection_string(conn_string)
                    database_name = conn_data['DATABASE']

                    if database['onServerName'] not in self.skip_names:
                        for dataset in database['datasets']:
                            dataset_name = dataset['onServerName']
                            svc_record = ServiceRecord(database_name, dataset_name, svc_name, svc_type, svc_url)

        return service_records

    def __get_service_records(self):

        service_records = []

        root_catalog = self.__make_request(self.admin_services_root)
        root_folders = root_catalog['folders']

        for folder_name in root_folders:

            if folder_name not in self.skip_folders:

                catalog_url = urllib.parse.urljoin(self.admin_services_root, folder_name)
                service_records += self.__build_service_records(catalog_url)

        return service_records

    def update_catalog(self):
        """Update the service catalog table in the database."""

        service_records = [rec.as_tuple() for rec in self.__get_service_records()]
        database_connection = self.__get_database_connection('utility')
        cursor = database_connection.cursor()

        # empty the existing table
        query_truncate = "TRUNCATE TABLE Utility.dbo.ServiceCatalog"

        # populate the table with current data
        query_insert = ("INSERT INTO Utility.dbo.ServiceCatalog ("
                        "DatabaseName, DatasetName, ServiceName, ServiceType, ServiceUrl) "
                        "VALUES (?, ?, ?, ?, ?)")
        cursor.executemany(query_insert, service_records)


0 Kudos