Project

Profile

Help

Task #3836

Convert from coreapi to pyswagger

Added by daviddavis over 2 years ago. Updated 5 months ago.

Status:
CLOSED - WONTFIX
Priority:
Normal
Assignee:
-
Sprint/Milestone:
Start date:
Due date:
% Done:

0%

Estimated time:
Platform Release:
Groomed:
Yes
Sprint Candidate:
No
Tags:
Sprint:
Quarter:

Description

Why do we need to convert to pyswagger?

The schema that we use for documentation and bindings are openapi based. PySwagger is a python swagger client that reads in schema, and makes calls to the REST API based on that schema.

Pyswagger makes it so we don't need to typecheck body parameters, and we don't need to format query and path parameters in URLs.

Creating the nested Click commands.

Every openapi operation has its own operationId. These OperationIds can be accessed from pyswagger like so:

app = App.create(DOCUMENT_PATH)
app.op.keys()

This returns something like:

['repositories!##!repositories_versions_removed_content',
'repositories!##!repositories_versions_content', 
'repositories!##!repositories_versions_added_content', 
'repositories!##!repositories_versions_delete', 
'repositories!##!repositories_versions_read', 
'repositories!##!repositories_versions_create', 
'repositories!##!repositories_versions_list', 
'repositories!##!repositories_partial_update', 
'repositories!##!repositories_delete', 
'repositories!##!repositories_update', 
'repositories!##!repositories_read', 
'repositories!##!repositories_create', 
'repositories!##!repositories_list',
'remotes!##!remotes_create',
...
]

Individual operations are separated via '_', this is less than ideal, since some of our operations contain '_' like 'added_content'.

A solution would be to separate this list with \, group all the common operations together (things to the left of \), and find the longest common startswith substring for any subset of the list (care should be taken that this substing has to be separated by a _, since we don't want repo_versions, and repositories to return repo as a substring).

This longest common substring should be a 'group' that other commands nest under. This substring should then be removed from the rest of the items in the the subset, and if there is no more shared substrings, everything can be added as a command.

Getting indivudual operation parameters

Individual parameters can be found on

app.op['repositories!##!repositories_update'].parameters

Usually this is a data parameter (for body params) and whatever path params are in the URL.

The data param has a schema reference that can be accessed

getattr(app.op['repositories!##!repositories_create'].parameters[0].schema, '$ref')

And a pyswagger Resolver can be used to load up that reference and get the necessary parameters

>>> from pyswagger.resolve import Resolver
>>> res = Resolver()
>>> res.resolve(getattr(app.op['repositories!##!repositories_create'].parameters[0].schema, '$ref'))
{  
    'required':[  
        'name'
    ],
    'type':'object',
    'properties':{  
        'id':{  
            'title':'Id',
            'type':'string',
            'format':'uuid',
            'readOnly':True
        },
        '_href':{  
            'title':' href',
            'type':'string',
            'format':'uri',
            'readOnly':True
        },
        'created':{  
            'title':'Created',
            'description':'Timestamp of creation.',
            'type':'string',
            'format':'date-time',
            'readOnly':True
        },
        '_versions_href':{  
            'title':' versions href',
            'type':'string',
            'format':'uri',
            'readOnly':True
        },
        '_latest_version_href':{  
            'title':' latest version href',
            'type':'string',
            'format':'uri',
            'readOnly':True
        },
        'name':{  
            'title':'Name',
            'description':'A unique name for this repository.',
            'type':'string',
            'minLength':1
        },
        'description':{  
            'title':'Description',
            'description':'An optional description.',
            'type':'string'
        },
        'notes':{  
            'title':'Notes',
            'description':'A mapping of string keys to string values, for storing notes on this object.',
            'type':'object',
            'additionalProperties':{  
                'type':'string',
                'minLength':1
            }
        }
    }
}

Checklist


Related issues

Related to Pulp CLI - Issue #3839: Handle file parametersCLOSED - WONTFIX<a title="Actions" class="icon-only icon-actions js-contextmenu" href="#">Actions</a>

History

#1 Updated by daviddavis over 2 years ago

  • Description updated (diff)

#2 Updated by daviddavis over 2 years ago

  • Sprint/Milestone set to Proof of concept

#3 Updated by bizhang over 2 years ago

  • Description updated (diff)

#4 Updated by bizhang over 2 years ago

  • Sprint Candidate changed from No to Yes

#5 Updated by bizhang over 2 years ago

#6 Updated by CodeHeeler over 2 years ago

  • Groomed changed from No to Yes

#7 Updated by daviddavis over 2 years ago

A couple concerns with the nesting. Suppose I have a path like "a/b_c/d" with it's the only endpoint under b_c. The operation id would be "ab_c_d". How would the CLI know to form the command pulp a b_c d and not pulp a b_c_d?

Also, if you had the paths "/z/a/b_c/" and "/z/a_b/d" which would form the operations "za_b_c" and "aa_b_d", I think they would incorrectly get nested together under pulp z a_b.

I guess these issues aren't a big deal if we assume nesting is based on commonalities in operation names and not paths in the REST API.

Alternatively though, I think we could potentially look at the path property (e.g. /repositories/{repository_pk}/versions/{number}/added_content/) on app.op values to decide how to nest commands.

#8 Updated by bizhang over 2 years ago

The operation id for POSTing to /artifacts/ is artifacts_create, and the operation id for GET /artifacts/ is artifacts_list, and the operation id for GET /artifacts/{id}/ is artifacts_read.
If we go off the path id, we also have to take available REST verbs into account (map POST-> create, GET->{list, read} depending on context).

The best solution is probably use a combination of both the path and the operation ids.

Path can be split on '/' and used to construct the nested CLI groups, and the operation ids can be used to get the commands (read, list, delete, update, etc). available to these groups.

There is some complexity in the case of 'repositories_versions_added_content' since it doesn't have any additional commands so added_content would have to be a command on repositories versions instead of an additional group.

#9 Updated by bizhang over 2 years ago

  • Description updated (diff)

#10 Updated by daviddavis over 2 years ago

Sounds good. +1.

#11 Updated by dkliban@redhat.com over 2 years ago

  • Sprint set to Sprint 40

#12 Updated by bizhang over 2 years ago

  • Status changed from NEW to ASSIGNED
  • Assignee set to bizhang

#13 Updated by rchan about 2 years ago

  • Sprint changed from Sprint 40 to Sprint 41

#14 Updated by bizhang about 2 years ago

  • Status changed from ASSIGNED to NEW
  • Assignee deleted (bizhang)

Unassigning since the pulp3 CLI work has been deprioritized

#15 Updated by daviddavis about 2 years ago

  • Sprint deleted (Sprint 41)

#16 Updated by daviddavis about 2 years ago

  • Sprint Candidate changed from Yes to No

#17 Updated by daviddavis 6 months ago

  • Status changed from NEW to CLOSED - WONTFIX

Please register to edit this issue

Also available in: Atom PDF