Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 0.32.0
current_version = 0.34.0
commit = True
tag = True

Expand Down
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,17 @@

SPDX-License-Identifier: MIT

version="0.32.0"
version="0.34.0"

What's New?
===========

01-Aug-2025 0.34
* New - first attempt at support for resources - for DN only at the moment. The aim is to simplify accessing and modifying properties of an artifact: you can get a python object for an artifact and access its properties as attributes of the object, e.g. req.Identifier. See dn_resource_test.py. Print the resource to see the modifiable and unmodifiable attributes. If you modify an (modifiable) attribute you can put() the resource to update it in DOORS Next. Modules can be resources but no possibility to modify the structure. You can add (DN->DN) links. You can see and modify the folder a core artifact is in.
* New query methods (see resource.py) to simplify querying and get resources back.
* Also fixed smaller bugs like the one introduced by Python 13 accepting quotes inside f-strings, which only showed up if you used Python <13
* An attribute name can now be used in the oslcquery -s option, like -s "'Child Of'" (Windows) which used to give an error

16-Dec-2024
* Authentication using Application passwords now works - for OIDC and SAML-backed authentication providers (OP) - but note below how this has been implemented to perhaps work around the fact that application passwords only work with a single app, os if you want to talk to more than one app, e.g. rm and gc, you have to acquire and specify a password per app. Not extensively tested, please let me know if it works/doesn't work for you!.

Expand Down
5 changes: 3 additions & 2 deletions elmclient/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

# scan for extensions to import and extend the specified class
# extensions are .py file with a name like <classname>-something.py e.g RMApp-extension.py
# the classes in the file are added as base classes to the extended class
# the classes in the file are added as base classes (i.e. additional mixins) to the extended class
# so it's dynamic mixins :-)
# A mixin may override existing methods but the main aim is to add new methods for that class
def load_extensions( *, path=None, folder=None ):
Expand Down Expand Up @@ -65,8 +65,9 @@ def load_extensions( *, path=None, folder=None ):
# add them to the extended class so they precede (i.e. may override) the previous base classes
for n,c in extenderclasses.items():
# add to bases
print( f"Extending {extendedclass} with {c}" )
extendedclass.__bases__ = (c,)+extendedclass.__bases__

## load any local extensions
#load_extensions()
load_extensions()

2 changes: 1 addition & 1 deletion elmclient/__meta__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

app = 'elmoslcquery'
description = 'Commandline OSLC query for ELM'
version = '0.32.0'
version = '0.34.0'
license = 'MIT'
author_name = 'Ian Barnard'
author_mail = 'ian.barnard@uk.ibm.com'
Expand Down
7 changes: 4 additions & 3 deletions elmclient/_ccm.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
from . import rdfxml
from . import server
from . import utils
from . import resource

#################################################################################################

Expand All @@ -39,7 +40,7 @@ def callers():

#################################################################################################

class CCMProject(_project._Project):
class CCMProject( _project._Project , resource.Resources_Mixin):
def __init__(self, name, project_uri, app, is_optin,singlemode):
super().__init__(name, project_uri, app, is_optin,singlemode)
self.default_query_resource = 'oslc_cm1:ChangeRequest'
Expand Down Expand Up @@ -130,7 +131,7 @@ def _load_type_from_resource_shape(self, el, supershape=None):
altname = None

logger.info( f"Defining property {title}.{property_title} {altname=} {propuri=} +++++++++++++++++++++++++++++++++++++++" )
self.register_property(property_title,propuri, shape_uri=uri, altname=altname,property_definition_uri=property_definition_uri)
self.register_property(property_title,propuri, altname=altname,property_definition_uri=property_definition_uri, shape_uri=uri)

allowedvaluesu = rdfxml.xmlrdf_get_resource_uri(real_propel, ".//oslc:allowedValues" )
if allowedvaluesu is not None:
Expand Down Expand Up @@ -175,7 +176,7 @@ def _load_type_from_resource_shape(self, el, supershape=None):
# register this shape as an rtc_cm:type enum
logger.info( f"Defining category rtc_cm:type {enum_value_name} {enum_id} {category} {enum_uri}" )
# ensure the rtc_cm:type property is defined (but don't overwrite existing definition)
self.register_property( 'rtc_cm:type', 'rtc_cm:type', do_not_overwrite=True )
self.register_property( 'rtc_cm:type', 'rtc_cm:type', do_not_overwrite=True, shape_uri=uri )
# add the shape to it using the shape's URI as an enum URI
# NOTE the use of the id - this id is used when comparing values with rtc_cm_type to see workaround https://jazz.net/forum/questions/86619/oslc-20-query-with-oslcwhere-parameter-dctermstype-returns-400-unknown-attribute-id
self.register_enum( enum_value_name, enum_uri, 'rtc_cm:type',id=enum_id )
Expand Down
2 changes: 1 addition & 1 deletion elmclient/_customScenarios.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def getRunningScenarios( self ):
LOGLEVEL = os.environ.get("QUERY_LOGLEVEL" ,None )

# setup arghandler
parser = argparse.ArgumentParser(description="Perform OSLC query on a Jazz application, with results output to CSV (and other) formats - use -h to get some basic help")
parser = argparse.ArgumentParser(description="Test harness for CusgtomScenarios")

parser.add_argument('action', choices=['start','stop','status'], help=f'start/stop/status')
parser.add_argument('name', default=None, nargs='?', help=f'The anme of the scenario - only relevant for the start and stop actions')
Expand Down
12 changes: 6 additions & 6 deletions elmclient/_gcm.py
Original file line number Diff line number Diff line change
Expand Up @@ -610,7 +610,7 @@ def _generic_load_type_from_resource_shape(self, el, supershape=None):

if pd_u is not None:
if not pd_u.startswith( self.baseurl ):
self.register_property(property_title,pd_u, shape_uri=uri, altname=altname)
self.register_property(property_title,pd_u, altname=altname, shape_uri=uri)
logger.debug( f"+++++++Skipping non-local Property Definition {pd_u}" )
continue
else:
Expand All @@ -620,7 +620,7 @@ def _generic_load_type_from_resource_shape(self, el, supershape=None):
logger.debug( f"ALREADY KNOWN2" )
continue
logger.info( f"Defining property {title}.{property_title} {altname=} {pd_u=} +++++++++++++++++++++++++++++++++++++++" )
self.register_property(property_title,pd_u, shape_uri=uri, altname=altname)
self.register_property(property_title,pd_u, altname=altname, shape_uri=uri)
# check for any allowed value
allowedvalueu = rdfxml.xmlrdf_get_resource_uri(real_propel, ".//oslc:allowedValue" )
if allowedvalueu is not None:
Expand Down Expand Up @@ -707,8 +707,8 @@ def resolve_uri_to_name(self, uri, prefer_same_as=True, dontpreferhttprdfrui=Tru

# for OSLC query, given an attribute (property) name return its type URI
# the context is the shape definition - can be None, needed to be specified ultimately by the user when property names aren't unique
def resolve_property_name_to_uri(self, name, shapeuri=None, exception_if_not_found=True):
logger.info( f"resolve_property_name_to_uri {name=} {shapeuri=}" )
result = self.get_property_uri(name,shape_uri=shapeuri)
logger.info( f"resolve_property_name_to_uri {name=} {shapeuri=} {result=}" )
def resolve_property_name_to_uri(self, name, exception_if_not_found=True):
logger.info( f"resolve_property_name_to_uri {name=} " )
result = self.get_property_uri(name)
logger.info( f"resolve_property_name_to_uri {name=} {result=}" )
return result
18 changes: 10 additions & 8 deletions elmclient/_newtypesystem.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,9 +285,10 @@ def load_ot( self, serverconnection, url, iscacheable=True, isused=False ):
print( f"OT definition for {url} already present!" )
return
# get the URI and process all the attributes
content_x = serverconnection.execute_get_xml( url, params={'oslc_config.context':serverconnection.local_config},headers={'Configuration-Context': None}, cacheable=iscacheable )
content_x = serverconnection.execute_get_xml( url, params={'vvc.configuration':serverconnection.local_config},headers={'Configuration-Context': None}, cacheable=iscacheable )
if content_x is None:
burp
raise Exception( "No XML!" )

modified = rdfxml.xmlrdf_get_resource_uri( content_x,'.//dcterms:modified', exceptionifnotfound=True )
modifiedBy = rdfxml.xmlrdf_get_resource_uri( content_x,'.//dcterms:contributor', exceptionifnotfound=True )
# component = rdfxml.xmlrdf_get_resource_uri( content_x,'.//oslc_config:component', exceptionifnotfound=True )
Expand All @@ -313,9 +314,10 @@ def load_ad( self, serverconnection, url, iscacheable=True, isused=False ):
# print( f"AD definition for {url} already present!" )
return
# get the URI and process all the attributes
content_x = serverconnection.execute_get_xml( url, params={'oslc_config.context':serverconnection.local_config},headers={'Configuration-Context': None}, cacheable=iscacheable )
content_x = serverconnection.execute_get_xml( url, params={'vvc.configuration':serverconnection.local_config},headers={'Configuration-Context': None}, cacheable=iscacheable )
if content_x is None:
burp
raise Exception( "No XML!" )

modified = rdfxml.xmlrdf_get_resource_uri( content_x,'.//dcterms:modified', exceptionifnotfound=True )
modifiedBy = rdfxml.xmlrdf_get_resource_uri( content_x,'.//dcterms:contributor', exceptionifnotfound=True )
# component = rdfxml.xmlrdf_get_resource_uri( content_x,'.//oslc_config:component', exceptionifnotfound=True )
Expand All @@ -340,9 +342,9 @@ def load_at( self, serverconnection, url, iscacheable=True, isused=False ):
if not serverconnection.app.is_server_uri( url ):
# print( f"AT Ignoring non-server URL {url}" )
return
content_x = serverconnection.execute_get_xml( url, params={'oslc_config.context':serverconnection.local_config},headers={'Configuration-Context': None}, cacheable=iscacheable )
content_x = serverconnection.execute_get_xml( url, params={'vvc.configuration':serverconnection.local_config},headers={'Configuration-Context': None}, cacheable=iscacheable )
if content_x is None:
burp
raise Exception( "No XML!" )
modified = rdfxml.xmlrdf_get_resource_uri( content_x,'.//dcterms:modified', exceptionifnotfound=True )
modifiedBy = rdfxml.xmlrdf_get_resource_uri( content_x,'.//dcterms:contributor', exceptionifnotfound=True )
# component = rdfxml.xmlrdf_get_resource_uri( content_x,'.//oslc_config:component', exceptionifnotfound=True )
Expand Down Expand Up @@ -386,9 +388,9 @@ def load_lt( self, serverconnection, url, iscacheable=True, isused=False ):
if url in self.lts:
# print( f"LT definition for {url} already present!" )
return
content_x = serverconnection.execute_get_xml( url, params={'oslc_config.context':serverconnection.local_config},headers={'Configuration-Context': None}, cacheable=iscacheable )
content_x = serverconnection.execute_get_xml( url, params={'vvc.configuration':serverconnection.local_config},headers={'Configuration-Context': None}, cacheable=iscacheable )
if content_x is None:
burp
raise Exception( "No XML!" )
modified = rdfxml.xmlrdf_get_resource_uri( content_x,'.//dcterms:modified', exceptionifnotfound=True )
modifiedBy = rdfxml.xmlrdf_get_resource_uri( content_x,'.//dcterms:contributor', exceptionifnotfound=True )
# component = rdfxml.xmlrdf_get_resource_uri( content_x,'.//oslc_config:component', exceptionifnotfound=True )
Expand Down
Loading