-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
tree-wide: add support for ABAP DDIC Data Element CRUD
- Loading branch information
Libor Bucek
committed
Sep 19, 2023
1 parent
b251600
commit ecbf301
Showing
10 changed files
with
1,052 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
# Data Element | ||
|
||
- [Data Element](#data-element) | ||
- [define](#define) | ||
|
||
## define | ||
|
||
Define an ABAP DDIC Data Element. | ||
|
||
```bash | ||
sapcli dataelement define DATA_ELEMENT_NAME --type=domain|predefinedAbapType [--corrnr TRANSPORT] [--activate] [--no-error-existing] [--domain_name] [--data_type] [--data_type_length] [--data_type_decimals] [--label_short] [--label_medium] [--label_long] [--label_heading] | ||
``` | ||
|
||
* _DATA\_ELEMENT\_NAME_ specifying the name of the data element | ||
* _--type [domain|predefinedAbapType]_ type kind | ||
* _--domain\_name_ domain name (e.g. BUKRS) [default = ''] - mandatory in case the _--type_=domain **(optional)** | ||
* _--data\_type_ data type (e.g. CHAR) [default = ''] - mandatory in case the _--type_=predefinedAbapType **(optional)** | ||
* _--data\_type\_length_ data type length (e.g. 5) [default = '0'] **(optional)** | ||
* _--data\_type\_decimals_ data type decimals (e.g. 3) [default = '0'] **(optional)** | ||
* _--label\_short_ short label [default = ''] **(optional)** | ||
* _--label\_medium_ medium label [default = ''] **(optional)** | ||
* _--label\_long_ long label [default = ''] **(optional)** | ||
* _--label\_heading_ heading label [default = ''] **(optional)** | ||
* _--corrnr TRANSPORT_ specifies CTS Transport Request Number **(optional)** | ||
* _--activate_ activate after finishing the data element modification **(optional)** | ||
* _--no-error-existing_ do not fail if data element already exists **(optional)** |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,185 @@ | ||
"""ABAP Data Element ADT functionality module""" | ||
|
||
from sap.adt.objects import ADTObject, ADTObjectType, ADTCoreData, ADTObjectSourceEditor | ||
# pylint: disable=unused-import | ||
from sap.adt.annotations import OrderedClassMembers, xml_element, xml_text_node_property | ||
from sap.adt.objects import XMLNamespace, XMLNS_ADTCORE | ||
from sap.errors import SAPCliError | ||
|
||
XMLNS_DTEL = XMLNamespace('dtel', 'http://www.sap.com/adt/dictionary/dataelements') | ||
|
||
LABELS_LENGTH = { | ||
'short': '10', | ||
'medium': '20', | ||
'long': '40', | ||
'heading': '55' | ||
} | ||
|
||
|
||
class ADTDataElementData(ADTCoreData): | ||
"""Data Element nodes data. | ||
""" | ||
|
||
# pylint: disable=too-many-instance-attributes | ||
# pylint: disable=too-few-public-methods | ||
class DataElement(metaclass=OrderedClassMembers): | ||
"""ADT Data Element data collector""" | ||
|
||
type = xml_text_node_property('dtel:typeKind') | ||
type_name = xml_text_node_property('dtel:typeName') | ||
data_type = xml_text_node_property('dtel:dataType') | ||
data_type_length = xml_text_node_property('dtel:dataTypeLength') | ||
data_type_decimals = xml_text_node_property('dtel:dataTypeDecimals') | ||
label_short = xml_text_node_property('dtel:shortFieldLabel') | ||
label_short_length = xml_text_node_property('dtel:shortFieldLength') | ||
label_short_max_length = xml_text_node_property('dtel:shortFieldMaxLength') | ||
label_medium = xml_text_node_property('dtel:mediumFieldLabel') | ||
label_medium_length = xml_text_node_property('dtel:mediumFieldLength') | ||
label_medium_max_length = xml_text_node_property('dtel:mediumFieldMaxLength') | ||
label_long = xml_text_node_property('dtel:longFieldLabel') | ||
label_long_length = xml_text_node_property('dtel:longFieldLength') | ||
label_long_max_length = xml_text_node_property('dtel:longFieldMaxLength') | ||
label_heading = xml_text_node_property('dtel:headingFieldLabel') | ||
label_heading_length = xml_text_node_property('dtel:headingFieldLength') | ||
label_heading_max_length = xml_text_node_property('dtel:headingFieldMaxLength') | ||
search_help = xml_text_node_property('dtel:searchHelp') | ||
search_help_parameter = xml_text_node_property('dtel:searchHelpParameter') | ||
set_get_parameter = xml_text_node_property('dtel:setGetParameter') | ||
default_component_name = xml_text_node_property('dtel:defaultComponentName') | ||
deactivate_input_history = xml_text_node_property('dtel:deactivateInputHistory') | ||
change_document = xml_text_node_property('dtel:changeDocument') | ||
left_to_right_direction = xml_text_node_property('dtel:leftToRightDirection') | ||
deactivate_bidi_filtering = xml_text_node_property('dtel:deactivateBIDIFiltering') | ||
|
||
# pylint: disable=too-many-arguments | ||
def __init__(self, package=None, description=None, language=None, | ||
master_language=None, master_system=None, responsible=None, | ||
package_reference=None, abap_language_version=None): | ||
super().__init__(package, description, language, | ||
master_language, master_system, responsible, | ||
package_reference, abap_language_version) | ||
|
||
self._data_element = ADTDataElementData.DataElement() | ||
|
||
@property | ||
def data_element(self): | ||
"""The Data Element's reference""" | ||
|
||
return self._data_element | ||
|
||
|
||
class DataElement(ADTObject): | ||
"""ABAP Data Element""" | ||
|
||
OBJTYPE = ADTObjectType( | ||
'DTEL/DE', | ||
'ddic/dataelements', | ||
XMLNamespace('blue', 'http://www.sap.com/wbobj/dictionary/dtel', parents=[XMLNS_ADTCORE, XMLNS_DTEL]), | ||
'application/vnd.sap.adt.dataelements.v2+xml', | ||
{ | ||
'application/vnd.sap.adt.dataelements.v2+xml': '', | ||
'application/vnd.sap.adt.dataelements.v1+xml': '' | ||
}, | ||
'wbobj', | ||
editor_factory=ADTObjectSourceEditor | ||
) | ||
|
||
def __init__(self, connection, name, package=None, metadata=None): | ||
super().__init__(connection, name, metadata, active_status='inactive') | ||
|
||
self._metadata = ADTDataElementData( | ||
metadata.package, metadata.description, | ||
metadata.language, metadata.master_language, | ||
metadata.master_system, metadata.responsible, | ||
metadata.package_reference.name if metadata.package_reference is not None else None, | ||
metadata.abap_language_version | ||
) if metadata is not None else ADTDataElementData() | ||
|
||
self._metadata.package_reference.name = package | ||
|
||
@xml_element('dtel:dataElement') | ||
def data_element(self): | ||
"""The Data Element's reference""" | ||
|
||
return self._metadata.data_element | ||
|
||
def set_type(self, value): | ||
"""Setter for Type Kind element""" | ||
|
||
self._metadata.data_element.type = value | ||
|
||
def set_type_name(self, value): | ||
"""Setter for Type Name element""" | ||
|
||
self._metadata.data_element.type_name = value.upper() if value is not None else None | ||
|
||
def set_data_type(self, value): | ||
"""Setter for Data Type element""" | ||
|
||
self._metadata.data_element.data_type = value.upper() if value is not None else None | ||
|
||
def set_data_type_length(self, value): | ||
"""Setter for Data Type Length element""" | ||
|
||
self._metadata.data_element.data_type_length = value | ||
|
||
def set_data_type_decimals(self, value): | ||
"""Setter for Data Type Decimals element""" | ||
|
||
self._metadata.data_element.data_type_decimals = value | ||
|
||
def set_label_short(self, value): | ||
"""Setter for Label Short element""" | ||
|
||
self._metadata.data_element.label_short = value | ||
|
||
def set_label_medium(self, value): | ||
"""Setter for Label Medium element""" | ||
|
||
self._metadata.data_element.label_medium = value | ||
|
||
def set_label_long(self, value): | ||
"""Setter for Label Long element""" | ||
|
||
self._metadata.data_element.label_long = value | ||
|
||
def set_label_heading(self, value): | ||
"""Setter for Label Heading element""" | ||
|
||
self._metadata.data_element.label_heading = value | ||
|
||
def normalize(self): | ||
"""Validate Data Element setup before save""" | ||
if self._metadata.data_element.type == 'domain': | ||
self._metadata.data_element.data_type = '' | ||
self._metadata.data_element.data_type_length = '0' | ||
self._metadata.data_element.data_type_decimals = '0' | ||
if self._metadata.data_element.type == 'predefinedAbapType': | ||
self._metadata.data_element.type_name = '' | ||
|
||
# pylint: disable=line-too-long | ||
self._metadata.data_element.label_short_length = self._metadata.data_element.label_short_length if not self._metadata.data_element.label_short_length else LABELS_LENGTH['short'] | ||
# pylint: disable=line-too-long | ||
self._metadata.data_element.label_medium_length = self._metadata.data_element.label_medium_length if not self._metadata.data_element.label_medium_length else LABELS_LENGTH['medium'] | ||
# pylint: disable=line-too-long | ||
self._metadata.data_element.label_long_length = self._metadata.data_element.label_long_length if not self._metadata.data_element.label_long_length else LABELS_LENGTH['long'] | ||
# pylint: disable=line-too-long | ||
self._metadata.data_element.label_heading_length = self._metadata.data_element.label_heading_length if not self._metadata.data_element.label_heading_length else LABELS_LENGTH['heading'] | ||
|
||
# pylint: disable=line-too-long | ||
self._metadata.data_element.deactivate_input_history = self._metadata.data_element.deactivate_input_history if self._metadata.data_element.deactivate_input_history is not None else False | ||
# pylint: disable=line-too-long | ||
self._metadata.data_element.change_document = self._metadata.data_element.change_document if self._metadata.data_element.change_document is not None else False | ||
# pylint: disable=line-too-long | ||
self._metadata.data_element.left_to_right_direction = self._metadata.data_element.left_to_right_direction if self._metadata.data_element.left_to_right_direction is not None else False | ||
# pylint: disable=line-too-long | ||
self._metadata.data_element.deactivate_bidi_filtering = self._metadata.data_element.deactivate_bidi_filtering if self._metadata.data_element.deactivate_bidi_filtering is not None else False | ||
|
||
def validate(self): | ||
"""Validate Data Element setup""" | ||
|
||
if self._metadata.data_element.type == 'domain' and not self._metadata.data_element.type_name: | ||
raise SAPCliError('Domain name must be provided (--domain_name) if the type (--type) is "domain"') | ||
if self._metadata.data_element.type == 'predefinedAbapType' and not self._metadata.data_element.data_type: | ||
# pylint: disable=line-too-long | ||
raise SAPCliError('Data type name must be provided (--data_type) if the type (--type) is "predefinedAbapType"') |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,109 @@ | ||
"""ADT proxy for ABAP DDIC Data Element""" | ||
|
||
import sap.adt | ||
from sap.adt.errors import ExceptionResourceAlreadyExists | ||
import sap.cli.object | ||
import sap.cli.wb | ||
import sap.cli.core | ||
|
||
|
||
class CommandGroup(sap.cli.object.CommandGroupObjectMaster): | ||
"""Adapter converting command line parameters to sap.adt.DataElement methods | ||
calls. | ||
""" | ||
|
||
def __init__(self): | ||
super().__init__('dataelement') | ||
|
||
self.define() | ||
|
||
def instance(self, connection, name, args, metadata=None): | ||
package = None | ||
if hasattr(args, 'package'): | ||
package = args.package | ||
|
||
return sap.adt.DataElement(connection, name.upper(), package=package, metadata=metadata) | ||
|
||
|
||
@CommandGroup.argument_corrnr() | ||
@CommandGroup.argument('--no-error-existing', action='store_true', default=False, | ||
help='Do not fail if data element already exists') | ||
@CommandGroup.argument('-a', '--activate', action='store_true', default=False, help='Activate after modification') | ||
@CommandGroup.argument('-t', '--type', required=True, choices=['domain', 'predefinedAbapType'], | ||
type=str, help='Type kind') | ||
@CommandGroup.argument('-d', '--domain_name', default=None, type=str, help='Domain name') | ||
@CommandGroup.argument('-dt', '--data_type', default=None, type=str, help='Data type') | ||
@CommandGroup.argument('-dtl', '--data_type_length', default='0', type=str, help='Data type length') | ||
@CommandGroup.argument('-dtd', '--data_type_decimals', default='0', type=str, help='Data type decimals') | ||
@CommandGroup.argument('-ls', '--label_short', default='', type=str, help='Short label') | ||
@CommandGroup.argument('-lm', '--label_medium', default='', type=str, help='Medium label') | ||
@CommandGroup.argument('-ll', '--label_long', default='', type=str, help='Long label') | ||
@CommandGroup.argument('-lh', '--label_heading', default='', type=str, help='Heading label') | ||
@CommandGroup.argument('package', help='Package assignment') | ||
@CommandGroup.argument('description', help='Data element description') | ||
@CommandGroup.argument('name', help='Data element name') | ||
@CommandGroup.command() | ||
def define(connection, args): | ||
"""Changes attributes of the given Data Element""" | ||
|
||
console = sap.cli.core.get_console() | ||
|
||
metadata = sap.adt.ADTCoreData(language='EN', master_language='EN', responsible=connection.user, | ||
description=args.description) | ||
|
||
dataelement = sap.adt.DataElement(connection, args.name.upper(), args.package, metadata=metadata) | ||
|
||
# Create Data Element | ||
console.printout(f'Creating data element {args.name}') | ||
try: | ||
dataelement.create(args.corrnr) | ||
except ExceptionResourceAlreadyExists as error: | ||
# Date Element already exists | ||
console.printout(f'Data element {args.name} already exists') | ||
if not args.no_error_existing: | ||
raise error | ||
|
||
# Fetch data element's content | ||
dataelement.fetch() | ||
|
||
if hasattr(args, 'type'): | ||
dataelement.set_type(args.type) | ||
|
||
if hasattr(args, 'domain_name'): | ||
dataelement.set_type_name(args.domain_name) | ||
|
||
if hasattr(args, 'data_type'): | ||
dataelement.set_data_type(args.data_type) | ||
|
||
if hasattr(args, 'data_type_length'): | ||
dataelement.set_data_type_length(args.data_type_length) | ||
|
||
if hasattr(args, 'data_type_decimals'): | ||
dataelement.set_data_type_decimals(args.data_type_decimals) | ||
|
||
if hasattr(args, 'label_short'): | ||
dataelement.set_label_short(args.label_short) | ||
|
||
if hasattr(args, 'label_medium'): | ||
dataelement.set_label_medium(args.label_medium) | ||
|
||
if hasattr(args, 'label_long'): | ||
dataelement.set_label_long(args.label_long) | ||
|
||
if hasattr(args, 'label_heading'): | ||
dataelement.set_label_heading(args.label_heading) | ||
|
||
dataelement.normalize() | ||
|
||
dataelement.validate() | ||
|
||
# Push Data Element changes | ||
console.printout(f'Data element {args.name} setup performed') | ||
with dataelement.open_editor(corrnr=args.corrnr) as editor: | ||
editor.push() | ||
|
||
# Activate Data Element | ||
if args.activate: | ||
console.printout(f'Data element {args.name} activation performed') | ||
activator = sap.cli.wb.ObjectActivationWorker() | ||
sap.cli.object.activate_object_list(activator, ((args.name, dataelement),), count=1) |
Oops, something went wrong.