From 0b35ff50c5a949e856ce20e91afeac61a4536a24 Mon Sep 17 00:00:00 2001 From: rienafairefr Date: Sat, 1 Sep 2018 18:46:53 +0200 Subject: [PATCH 01/19] use appdirs in pyrebrickable-cli --- cli/rebrickable_cli/utils.py | 15 +++++++++++++-- cli/setup.py | 1 + 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/cli/rebrickable_cli/utils.py b/cli/rebrickable_cli/utils.py index fd12376..caeeb63 100644 --- a/cli/rebrickable_cli/utils.py +++ b/cli/rebrickable_cli/utils.py @@ -1,7 +1,16 @@ import json import os -DATA_PATH = os.path.expanduser('~/.rebrickable') +from appdirs import AppDirs + +config_dir = AppDirs('pyrebrickable').user_config_dir + +try: + os.makedirs(config_dir) +except OSError: + pass + +DATA_PATH = os.path.join(config_dir, 'config.json') def update_data(key, value, data_path=DATA_PATH): @@ -11,7 +20,7 @@ def update_data(key, value, data_path=DATA_PATH): def write_data(data, data_path=DATA_PATH): - with open(data_path, 'w') as data_file: + with open(data_path, 'w+') as data_file: json.dump(data, data_file) @@ -19,6 +28,8 @@ def get_data(data_path=DATA_PATH): try: with open(data_path, 'r') as data_file: return json.load(data_file) + except IOError: + return {} except ValueError: return {} diff --git a/cli/setup.py b/cli/setup.py index cd9a66b..49c1ecc 100644 --- a/cli/setup.py +++ b/cli/setup.py @@ -23,6 +23,7 @@ # http://pypi.python.org/pypi/setuptools REQUIRES = ["pyrebrickable_api", + 'appdirs', "click >=6"] setup( From 092505806bf9b4a8d639e3feee3acb3e257883a8 Mon Sep 17 00:00:00 2001 From: rienafairefr Date: Sat, 1 Sep 2018 23:13:25 +0200 Subject: [PATCH 02/19] refactor json types to single values --- patch_swagger.py | 199 ++++++++++++++++++++++++----------------------- 1 file changed, 102 insertions(+), 97 deletions(-) diff --git a/patch_swagger.py b/patch_swagger.py index e111af9..f736035 100755 --- a/patch_swagger.py +++ b/patch_swagger.py @@ -57,7 +57,7 @@ def get_typedef_array(cls): array: { "type": "object", "properties": { - "count": {"type": "integer"}, + "count": Integer, "results": { "type": "array", "items": { @@ -78,163 +78,168 @@ def get_typedef(cls, properties): def ref(cls): return {'$ref': "#/definitions/%s" % cls} + + Integer = {'type': 'integer'} + String = {'type': 'string'} + Boolean = {'type': 'boolean'} + Url = {'type': 'string', 'format': 'uri'} classes = { 'Color': { - "id": {"type": "integer"}, - "name": {"type": "string"}, - "rgb": {"type": "string"}, - "is_trans": {"type": "boolean"}, + "id": Integer, + "name": String, + "rgb": String, + "is_trans": Boolean, }, 'Theme': { - "id": {"type": "integer"}, - "parent_id": {"type": "integer"}, - "name": {"type": "string"}, + "id": Integer, + "parent_id": Integer, + "name": String, }, 'Set': { - "set_num": {"type": "string"}, - "name": {"type": "string"}, - "year": {"type": "integer"}, - "theme_id": {"type": "integer"}, - "num_parts": {"type": "integer"}, - "set_img_url": {"type": "string"}, - "set_url": {"type": "string"}, + "set_num": String, + "name": String, + "year": Integer, + "theme_id": Integer, + "num_parts": Integer, + "set_img_url": Url, + "set_url": Url, "last_modified_dt": {"type": "string", "format": "date-time"} }, 'Part': { - "part_num": {"type": "string"}, - "name": {"type": "string"}, - "part_cat_id": {"type": "integer"}, - "part_url": {"type": "string"}, - "part_img_url": {"type": "string"} + "part_num": String, + "name": String, + "part_cat_id": Integer, + "part_url": Url, + "part_img_url": Url }, 'InventoryPart': { - "id": {'type': 'integer'}, - "inv_part_id": {'type': 'integer'}, + "id": Integer, + "inv_part_id": Integer, "part": ref('Part'), "color": ref('Color') }, 'SetList': { - "id": {'type': 'integer'}, - "is_buildable": {'type': 'boolean'}, - "name": {'type': 'string'}, - "num_sets": {'type': 'integer'} + "id": Integer, + "is_buildable": Boolean, + "name": String, + "num_sets": Integer }, 'Moc': { - "set_num": {"type": "string"}, - "name": {"type": "string"}, - "year": {"type": "integer"}, - "theme_id": {'type': 'integer'}, - "num_parts": {'type': 'integer'}, - "moc_img_url": {"type": "string"}, - "moc_url": {"type": "string"}, - "designer_name": {"type": "string"}, - "designer_url": {"type": "string"} + "set_num": String, + "name": String, + "year": Integer, + "theme_id": Integer, + "num_parts": Integer, + "moc_img_url": Url, + "moc_url": Url, + "designer_name": String, + "designer_url": Url }, 'Badge': { - "id": {'type': 'integer'}, - "code": {'type': 'string'}, - "level": {'type': 'integer'}, - "name": {'type': 'string'}, - "descr": {'type': 'string'} + "id": Integer, + "code": String, + "level": Integer, + "name": String, + "descr": String }, 'PartList': { - "id": {'type': 'integer'}, - "is_buildable": {'type': 'boolean'}, - "name": {'type': 'string'}, - "num_parts": {'type': 'integer'} + "id": Integer, + "is_buildable": Boolean, + "name": String, + "num_parts": Integer }, 'LostPart': { - "lost_part_id": {'type': 'integer'}, - "lost_quantity": {'type': 'integer'}, + "lost_part_id": Integer, + "lost_quantity": Integer, "inv_part": ref('InventoryPart') }, 'PartListPart': { - "list_id": {'type': 'integer'}, - "quantity": {'type': 'integer'}, + "list_id": Integer, + "quantity": Integer, "part": ref('Part'), "color": ref('Color') }, 'SetListSet': { - "list_id": {'type': 'integer'}, - "quantity": {'type': 'integer'}, - "include_spares": {'type': 'boolean'}, + "list_id": Integer, + "quantity": Integer, + "include_spares": Boolean, "set": ref('Set'), }, 'PartCategory': { - "id": {"type": "integer"}, - "name": {"type": "string"}, - "part_count": {"type": "integer"} + "id": Integer, + "name": String, + "part_count": Integer }, 'Element': { "part": ref('Part'), "color": ref('Color'), - "element_id": {'type': 'string'}, - "design_id": {'type': 'string'}, - "element_img_url": {'type': 'string'}, - "part_img_url": {'type': 'string'} + "element_id": String, + "design_id": String, + "element_img_url": Url, + "part_img_url": Url }, 'AllPart': { - "quantity": {'type': 'integer'}, + "quantity": Integer, "part": ref('Part'), "color": ref('Color') } } non_array_classes = { 'BuildOptions': { - "ignore_minifigs": {'type': 'boolean'}, - "sort_by": {'type': 'integer'}, - "max_year": {'type': 'integer'}, - "inc_accessory": {'type': 'boolean'}, - "max_parts": {'type': 'integer'}, - "inc_official": {'type': 'boolean'}, - "inc_bmodels": {'type': 'boolean'}, - "inc_custom": {'type': 'boolean'}, - "color": {'type': 'integer'}, - "min_year": {'type': 'integer'}, - "min_parts": {'type': 'integer'}, - "ignore_altp": {'type': 'boolean'}, - "ignore_non_lego": {'type': 'boolean'}, - "inc_owned": {'type': 'boolean'}, - "ignore_print": {'type': 'boolean'}, - "inc_premium": {'type': 'boolean'}, - "ignore_mold": {'type': 'boolean'} + "ignore_minifigs": Boolean, + "sort_by": Integer, + "max_year": Integer, + "inc_accessory": Boolean, + "max_parts": Integer, + "inc_official": Boolean, + "inc_bmodels": Boolean, + "inc_custom": Boolean, + "color": Integer, + "min_year": Integer, + "min_parts": Integer, + "ignore_altp": Boolean, + "ignore_non_lego": Boolean, + "inc_owned": Boolean, + "ignore_print": Boolean, + "inc_premium": Boolean, + "ignore_mold": Boolean }, 'Build': { - "num_owned_less_ignored": {'type': 'integer'}, - "total_parts": {'type': 'integer'}, - "total_parts_less_ignored": {'type': 'integer'}, + "num_owned_less_ignored": Integer, + "total_parts": Integer, + "total_parts_less_ignored": Integer, "pct_owned": {'type': 'number', 'format': 'float'}, - "num_ignored": {'type': 'integer'}, + "num_ignored": Integer, "build_options": ref('BuildOptions'), - "num_missing": {'type': 'integer'} + "num_missing": Integer }, 'Rewards': { - "badges": {"type": "array", "items": {'type': 'integer'}}, - "points": {'type': 'integer'}, - "level": {'type': 'integer'} + "badges": {"type": "array", "items": Integer}, + "points": Integer, + "level": Integer }, 'Lego': { - "lost_set_parts": {'type': 'integer'}, - "total_set_parts": {'type': 'integer'}, - "total_sets": {'type': 'integer'}, - "all_parts": {'type': 'integer'}, - "total_loose_parts": {'type': 'integer'} + "lost_set_parts": Integer, + "total_set_parts": Integer, + "total_sets": Integer, + "all_parts": Integer, + "total_loose_parts": Integer }, 'Profile': { - "user_id": {'type': 'integer'}, - "username": {'type': 'string'}, - "email": {'type': 'string'}, - "real_name": {'type': 'string'}, + "user_id": Integer, + "username": String, + "email": String, + "real_name": String, "last_activity": {'type': 'string', 'format': 'date-time'}, - "last_ip": {'type': 'string'}, - "location": {'type': 'string'}, + "last_ip": String, + "location": String, "rewards": ref('Rewards'), "lego": ref('Lego'), - "avatar_img": {'type': 'string'} + "avatar_img": String }, 'UsersTokenResponse': { - "user_token": {'type': 'string'} + "user_token": String } } From a656905db1731a022decec782af32b5a6062a165 Mon Sep 17 00:00:00 2001 From: rienafairefr Date: Sat, 1 Sep 2018 23:13:32 +0200 Subject: [PATCH 03/19] PartColorsList --- patch_swagger.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/patch_swagger.py b/patch_swagger.py index f736035..e95698b 100755 --- a/patch_swagger.py +++ b/patch_swagger.py @@ -183,6 +183,14 @@ def ref(cls): "quantity": Integer, "part": ref('Part'), "color": ref('Color') + }, + 'PartColorsList': { + "num_sets": Integer, + "elements": {'type': 'array', 'items': Integer}, + "num_set_parts": Integer, + "color_id": Integer, + "part_img_url": Url, + "color_name": String } } non_array_classes = { @@ -278,7 +286,7 @@ def set_schema(url, schema, code='200', method='get'): set_schema('/api/v3/lego/themes/', ref('ArrayOfThemes')) set_schema('/api/v3/lego/mocs/{set_num}/parts/', ref('ArrayOfInventoryParts')) set_schema('/api/v3/lego/parts/', ref('ArrayOfParts')) - set_schema('/api/v3/lego/parts/{part_num}/colors/', ref('ArrayOfColors')) + set_schema('/api/v3/lego/parts/{part_num}/colors/', ref('ArrayOfPartColorsLists')) set_schema('/api/v3/lego/part_categories/', ref('ArrayOfPartCategories')) set_schema('/api/v3/lego/sets/', ref('ArrayOfSets')) set_schema('/api/v3/users/badges/', ref('ArrayOfBadges')) From 8c8bf16d77b6e51010b129aaf5ea9d4f35a60406 Mon Sep 17 00:00:00 2001 From: rienafairefr Date: Sun, 2 Sep 2018 23:51:17 +0200 Subject: [PATCH 04/19] PartColorsElement --- patch_swagger.py | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/patch_swagger.py b/patch_swagger.py index e95698b..5a49507 100755 --- a/patch_swagger.py +++ b/patch_swagger.py @@ -191,6 +191,14 @@ def ref(cls): "color_id": Integer, "part_img_url": Url, "color_name": String + }, + "PartColorsElement": { + 'num_sets': Integer, + 'elements': {'type': 'array', 'items': Integer}, + 'num_set_parts': Integer, + 'year_from': Integer, + 'part_img_url': Url, + 'year_to': Integer } } non_array_classes = { @@ -272,7 +280,7 @@ def set_schema(url, schema, code='200', method='get'): set_schema('/api/v3/lego/themes/{id}/', ref('Theme')) set_schema('/api/v3/lego/mocs/{set_num}/', ref('Moc')) set_schema('/api/v3/lego/parts/{part_num}/', ref('Part')) - set_schema('/api/v3/lego/parts/{part_num}/colors/{color_id}/', ref('Color')) + set_schema('/api/v3/lego/parts/{part_num}/colors/{color_id}/', ref('PartColorsElement')) set_schema('/api/v3/lego/part_categories/{id}/', ref('PartCategory')) set_schema('/api/v3/lego/sets/{set_num}/', ref('Set')) set_schema('/api/v3/users/badges/{id}/', ref('Badge')) From 61bf1cb24e5b6c79d5544ea919c4b1613b9d2c87 Mon Sep 17 00:00:00 2001 From: rienafairefr Date: Sun, 2 Sep 2018 23:51:49 +0200 Subject: [PATCH 05/19] TypedCommand --- cli/rebrickable_cli/cli.py | 305 ++++++++++++++++++++++++------------- patch_swagger.py | 14 +- 2 files changed, 212 insertions(+), 107 deletions(-) diff --git a/cli/rebrickable_cli/cli.py b/cli/rebrickable_cli/cli.py index 8423c6c..fb09369 100644 --- a/cli/rebrickable_cli/cli.py +++ b/cli/rebrickable_cli/cli.py @@ -4,9 +4,11 @@ from getpass import getpass import click +from click import Abort, ClickException from six.moves import input -from rebrickable_api import ApiClient, Configuration +from rebrickable_api import ApiClient, Configuration, Color, Element, Moc, PartCategory, Part, PartColorsElement, Set, \ + Theme, Badge, Build, PartListPart, PartList, Profile, SetList, SetListSet from rebrickable_api import LegoApi, UsersApi from rebrickable_api.rest import ApiException from rebrickable_cli.utils import update_data, get_data, DATA_PATH @@ -16,6 +18,7 @@ class UsersContext(object): def __init__(self, api, token): self.api = api self.token = token + self.setlist = None pass_client = click.make_pass_decorator(ApiClient) @@ -23,6 +26,29 @@ def __init__(self, api, token): pass_userscontext = click.make_pass_decorator(UsersContext) pass_usersapi = click.make_pass_decorator(UsersApi) +def GET(ctx, fun): + current_obj = fun() + if ctx.invoked_subcommand is None: + print(current_obj) + else: + ctx.obj = current_obj + + +class TypedResult(click.Group): + def __init__(self, *args, **kwargs): + self.type_ = kwargs.pop('type', None) + super(TypedResult, self).__init__(*args, **kwargs) + for attribute_name, attribute_type in self.type_.openapi_types.items(): + def get_type_cmd(this): + @click.command() + @click.make_pass_decorator(this.type_) + def type_cmd(obj): + print(getattr(obj, attribute_name)) + + return type_cmd + + self.add_command(get_type_cmd(self), name=attribute_name) + def get_api_client(): configuration = Configuration() @@ -127,18 +153,20 @@ def lego_colors_list(api): print(api.lego_colors_list()) -@lego.command(name='color') +@lego.group(cls=TypedResult, type=Color, invoke_without_command=True, name='color') @pass_legoapi +@click.pass_context @click.argument('id') -def lego_colors_read(api, id): - print(api.lego_colors_read(id=id)) +def lego_colors_read(ctx, api, id): + GET(ctx, lambda: api.lego_colors_read(id=id)) -@lego.command(name='element') +@lego.command(cls=TypedResult, type=Element, invoke_without_command=True, name='element') @pass_legoapi +@click.pass_context @click.argument('element_id') -def lego_elements_read(api, element_id): - print(api.lego_elements_read(element_id=element_id)) +def lego_elements_read(ctx, api, element_id): + GET(ctx, lambda: api.lego_elements_read(element_id=element_id)) @lego.group(name='mocs') @@ -158,11 +186,12 @@ def lego_mocs_parts_list(api, set_num): print(api.lego_mocs_parts_list(set_num=set_num)) -@lego_mocs.command(name='read') +@lego_mocs.command(cls=TypedResult, type=Moc, invoke_without_command=True, name='read') @pass_legoapi +@click.pass_context @click.argument('set_num') -def lego_mocs_read(api, set_num): - print(api.lego_mocs_read(set_num=set_num)) +def lego_mocs_read(ctx, api, set_num): + GET(ctx, lambda: api.lego_mocs_read(set_num=set_num)) @lego.command(name='part_categories') @@ -171,11 +200,12 @@ def lego_part_categories_list(api): print(api.lego_part_categories_list()) -@lego.command(name='part_category') +@lego.command(cls=TypedResult, type=PartCategory, invoke_without_command=True, name='part_category') @pass_legoapi +@click.pass_context @click.argument('id') -def lego_part_categories_read(api, id): - print(api.lego_part_categories_read(id=id)) +def lego_part_categories_read(ctx, api, id): + GET(ctx, lambda: api.lego_part_categories_read(id=id)) @lego_parts_colors.command(name='list') @@ -185,12 +215,13 @@ def lego_parts_colors_list(api, part_num): print(api.lego_parts_colors_list(part_num=part_num)) -@lego_parts_colors.command(name='read') +@lego_parts_colors.group(cls=TypedResult, type=PartColorsElement, invoke_without_command=True, name='read') @pass_legoapi +@click.pass_context @click.argument('color_id') @click.argument('part_num') -def lego_parts_colors_read(api, color_id, part_num): - print(api.lego_parts_colors_read(color_id=color_id, part_num=part_num)) +def lego_parts_colors_read(ctx, api, color_id, part_num): + GET(ctx, lambda: api.lego_parts_colors_read(color_id=color_id, part_num=part_num)) @lego_parts_colors_sets.command(name='list') @@ -207,11 +238,12 @@ def lego_parts_list(api): print(api.lego_parts_list()) -@lego.command(name='part') +@lego.command(cls=TypedResult, type=Part, invoke_without_command=True, name='part') @pass_legoapi +@click.pass_context @click.argument('part_num') -def lego_parts_read(api, part_num): - print(api.lego_parts_read(part_num=part_num)) +def lego_parts_read(ctx, api, part_num): + GET(ctx, lambda: api.lego_parts_read(part_num=part_num)) @lego.group(name='sets') @@ -249,11 +281,12 @@ def lego_sets_parts_list(api, set_num): print(api.lego_sets_parts_list(set_num=set_num)) -@lego.command(name='set') +@lego.command(cls=TypedResult, type=Set, invoke_without_command=True, name='set') @pass_legoapi +@click.pass_context @click.argument('set_num') -def lego_sets_read(api, set_num): - print(api.lego_sets_read(set_num=set_num)) +def lego_sets_read(ctx, api, set_num): + GET(ctx, lambda: api.lego_sets_read(set_num=set_num)) @lego_sets.group(name='sets') @@ -274,11 +307,12 @@ def lego_themes_list(api): print(api.lego_themes_list()) -@lego.command(name='theme') +@lego.command(cls=TypedResult, type=Theme, invoke_without_command=True, name='theme') @pass_legoapi +@click.pass_context @click.argument('id') -def lego_themes_read(api, id): - print(api.lego_themes_read(id=id)) +def lego_themes_read(ctx, api, id): + GET(ctx, lambda: api.lego_themes_read(id=id)) @users.group(name='allparts') @@ -298,19 +332,21 @@ def users_badges_list(users_context): print(users_context.api.users_badges_list()) -@users.command(name='badge') +@users.command(cls=TypedResult, type=Badge, invoke_without_command=True, name='badge') @pass_userscontext +@click.pass_context @click.argument('id') -def users_badges_read(users_context, id): - print(users_context.api.users_badges_read(id=id)) +def users_badges_read(ctx, users_context, id): + GET(ctx, lambda: users_context.api.users_badges_read(id=id)) -@users.command(name='build') +@users.command(cls=TypedResult, type=Build, invoke_without_command=True, name='build') @pass_userscontext +@click.pass_context @click.argument('set_num') -def users_build_read(users_context, set_num): - print(users_context.api.users_build_read(user_token=users_context.token, - set_num=set_num)) +def users_build_read(ctx, users_context, set_num): + GET(ctx, lambda: users_context.api.users_build_read(user_token=users_context.token, + set_num=set_num)) @users.group(name='lost_parts') @@ -416,15 +452,16 @@ def users_partlists_parts_list(users_context, list_id): print(users_context.api.users_partlists_parts_list(user_token=users_context.token, list_id=list_id)) -@users_partlists_parts.command(name='read') +@users_partlists_parts.command(cls=TypedResult, type=PartListPart, invoke_without_command=True, name='read') @pass_userscontext +@click.pass_context @click.argument('color_id') @click.argument('list_id') @click.argument('part_num') -def users_partlists_parts_read(users_context, color_id, list_id, part_num): - print( - users_context.api.users_partlists_parts_read(user_token=users_context.token, color_id=color_id, list_id=list_id, - part_num=part_num)) +def users_partlists_parts_read(ctx, users_context, color_id, list_id, part_num): + GET(ctx, lambda: users_context.api.users_partlists_parts_read(user_token=users_context.token, color_id=color_id, + list_id=list_id, + part_num=part_num)) @users_partlists_parts.command(name='update') @@ -439,11 +476,12 @@ def users_partlists_parts_update(users_context, color_id, list_id, part_num, qua quantity=quantity)) -@users_partlists.command(name='read') +@users_partlists.command(cls=TypedResult, type=PartList, invoke_without_command=True, name='read') @pass_userscontext +@click.pass_context @click.argument('list_id') -def users_partlists_read(users_context, list_id): - print(users_context.api.users_partlists_read(users_context.token, list_id=list_id)) +def users_partlists_read(ctx, users_context, list_id): + GET(ctx, lambda: users_context.api.users_partlists_read(users_context.token, list_id=list_id)) @users_partlists.command(name='update') @@ -460,15 +498,30 @@ def users_parts_list(users_context): print(users_context.api.users_parts_list(user_token=users_context.token)) -@users.command(name='profile') +@users.group(cls=TypedResult, type=Profile, invoke_without_command=True, name='profile') @pass_userscontext -def users_profile_list(users_context): - print(users_context.api.users_profile_list(user_token=users_context.token)) +@click.pass_context +def users_profile_get(ctx, users_context): + GET(ctx, lambda: users_context.api.users_profile_list(user_token=users_context.token)) -@users.group('setlists') -def users_setlists(): - pass +@users.group('setlists', invoke_without_command=True) +@pass_userscontext +@click.pass_context +def users_setlists(ctx, users_context): + if ctx.invoked_subcommand is None: + print(users_context.api.users_setlists_list(user_token=users_context.token)) + + +@users.group('setlist', cls=TypedResult, type=SetList, invoke_without_command=True) +@click.argument('list_id') +@pass_userscontext +@click.pass_context +def users_setlist(ctx, users_context, list_id): + setlist = users_context.api.users_setlists_read(user_token=users_context.token, list_id=list_id) + ctx.obj = setlist + if ctx.invoked_subcommand is None: + GET(ctx, lambda: users_context.api.users_setlists_read(user_token=users_context.token, list_id=setlist.id)) @users_setlists.command(name='create') @@ -478,71 +531,81 @@ def users_setlists_create(users_context, name): print(users_context.api.users_setlists_create(user_token=users_context.token, name=name)) -@users_setlists.command(name='delete') -@pass_userscontext -@click.argument('list_id') -def users_setlists_delete(users_context, list_id): - print(users_context.api.users_setlists_delete(user_token=users_context.token, list_id=list_id)) +def setlist_command(fun): + @pass_userscontext + def new_fun(users_context, *args, **kwargs): + setlist = users_context.setlist + if setlist is not None: + fun(*args, **kwargs) + else: + raise ClickException('need a list_id !') + return new_fun -@users_setlists.command(name='list') +@users_setlist.command(name='delete') @pass_userscontext -def users_setlists_list(users_context): - print(users_context.api.users_setlists_list(user_token=users_context.token)) +@click.pass_context +def users_setlists_delete(ctx, users_context): + setlist = ctx.find_object(SetList) + print(users_context.api.users_setlists_delete(user_token=users_context.token, list_id=setlist.id)) -@users_setlists.group(name='partial') +@users_setlist.group(name='partial') def users_setlists_partial(): pass -@users_setlists_partial.command(name='update') +@users_setlist.command(name='update') @pass_userscontext -@click.argument('list_id') -def users_setlists_partial_update(users_context, list_id): - print(users_context.api.users_setlists_partial_update(user_token=users_context.token, list_id=list_id)) +@click.pass_context +def users_setlists_partial_update(ctx, users_context): + setlist = ctx.find_object(SetList) + print(users_context.api.users_setlists_partial_update(user_token=users_context.token, list_id=setlist.id)) -@users_setlists.command(name='read') +@users_setlist.group(name='sets', invoke_without_command=True) @pass_userscontext -@click.argument('list_id') -def users_setlists_read(users_context, list_id): - print(users_context.api.users_setlists_read(user_token=users_context.token, list_id=list_id)) +@click.pass_context +def users_setlists_sets(ctx, users_context): + setlist = ctx.find_object(SetList) + if ctx.invoked_subcommand is None: + print(users_context.api.users_setlists_sets_list(user_token=users_context.token, list_id=setlist.id)) -@users_setlists.group(name='sets') -def users_setlists_sets(): - pass +@users_setlist.group(name='set', cls=TypedResult, type=SetListSet, invoke_without_command=True) +@pass_userscontext +@click.pass_context +@click.argument('set_num') +def users_setlists_sets(ctx, users_context, set_num): + setlist = ctx.find_object(SetList) + if ctx.invoked_subcommand is None: + setlistset = users_context.api.users_setlists_sets_read(user_token=users_context.token, list_id=setlist.id, set_num=set_num) + ctx.obj = setlistset + GET(ctx, lambda: setlistset) @users_setlists_sets.command(name='create') @pass_userscontext -@click.argument('list_id') +@click.pass_context @click.argument('set_num') -def users_setlists_sets_create(users_context, list_id, set_num): +def users_setlists_sets_create(ctx, users_context, set_num): + setlist = ctx.find_object(SetList) print(users_context.api.users_setlists_sets_create(user_token=users_context.token, - list_id=list_id, + list_id=setlist.id, set_num=set_num)) @users_setlists_sets.command(name='delete') @pass_userscontext -@click.argument('list_id') -@click.argument('set_num') -def users_setlists_sets_delete(users_context, list_id, set_num): +@click.pass_context + +def users_setlists_sets_delete(ctx, users_context, set_num): + setlist = ctx.find_object(SetList) print(users_context.api.users_setlists_sets_delete(user_token=users_context.token, - list_id=list_id, + list_id=setlist.id, set_num=set_num)) -@users_setlists_sets.command(name='list') -@pass_userscontext -@click.argument('list_id') -def users_setlists_sets_list(users_context, list_id): - print(users_context.api.users_setlists_sets_list(user_token=users_context.token, - list_id=list_id)) - - @users_setlists_sets.group() def users_setlists_sets_partial(): pass @@ -550,61 +613,90 @@ def users_setlists_sets_partial(): @users_setlists_sets_partial.command(name='update') @pass_userscontext -@click.argument('list_id') +@click.pass_context @click.argument('set_num') -def users_setlists_sets_partial_update(users_context, list_id, set_num): +def users_setlists_sets_partial_update(ctx, users_context, set_num): + setlist = ctx.find_object(SetList) print(users_context.api.users_setlists_sets_partial_update(user_token=users_context.token, - list_id=list_id, + list_id=setlist.id, set_num=set_num)) -@users_setlists_sets.command(name='read') +@users_setlists_sets.command(cls=TypedResult, type=SetListSet, invoke_without_command=True, name='read') @pass_userscontext -@click.argument('list_id') +@click.pass_context @click.argument('set_num') -def users_setlists_sets_read(users_context, list_id, set_num): - print(users_context.api.users_setlists_sets_read(user_token=users_context.token, - list_id=list_id, - set_num=set_num)) +def users_setlists_sets_read(ctx, users_context, set_num): + setlist = ctx.find_object(SetList) + GET(ctx, lambda: users_context.api.users_setlists_sets_read(user_token=users_context.token, + list_id=setlist.id, + set_num=set_num)) @users_setlists_sets.command(name='update') @pass_userscontext -@click.argument('list_id') +@click.pass_context @click.argument('set_num') -def users_setlists_sets_update(users_context, list_id, set_num): +def users_setlists_sets_update(ctx, users_context, set_num): + setlist = ctx.find_object(SetList) print(users_context.api.users_setlists_sets_update(user_token=users_context.token, - list_id=list_id, + list_id=setlist.id, set_num=set_num)) @users_setlists.command(name='update') @pass_userscontext -@click.argument('list_id') +@click.pass_context @click.argument('name') -def users_setlists_update(users_context, list_id, name): +def users_setlists_update(ctx, users_context, name): + setlist = ctx.find_object(SetList) print(users_context.api.users_setlists_update(user_token=users_context.token, - list_id=list_id, + list_id=setlist.id, name=name)) -@users.group(name='sets') -def users_sets(): - pass +@users.group(name='sets', invoke_without_command=True) +@pass_userscontext +@click.pass_context +@click.option('--set_num', expose_value=False) +@click.option('--theme_id', expose_value=False) +@click.option('--min_year', expose_value=False) +@click.option('--max_year', expose_value=False) +@click.option('--min_parts', expose_value=False) +@click.option('--max_parts', expose_value=False) +@click.option('--search', expose_value=False) +def users_sets(ctx, users_context, *args, **kwargs): + if ctx.invoked_subcommand is None: + print(users_context.api.users_sets_list(users_context.token, *args, **kwargs)) + + +@users.group(name='set', cls=TypedResult, type=SetListSet, invoke_without_command=True) +@pass_userscontext +@click.pass_context +@click.argument('set_num') +def users_set(ctx, users_context, set_num): + set = users_context.api.users_sets_read(user_token=users_context.token, set_num=set_num) + ctx.obj = set + if ctx.invoked_subcommand is None: + GET(ctx, lambda: set) @users_sets.command(name='create') @pass_userscontext @click.argument('set_num') def users_sets_create(users_context, set_num): - print(users_context.api.users_sets_create(user_token=users_context.token, + try: + print(users_context.api.users_sets_create(user_token=users_context.token, set_num=set_num)) + except ApiException, e: + print('an error occured: %s, %s, %s' % (e.status, e.body, e.message)) -@users_sets.command(name='delete') +@users_set.command(name='delete') @pass_userscontext -@click.argument('set_num') -def users_sets_delete(users_context, set_num): +@click.pass_context +def users_sets_delete(ctx, users_context): + setlistset = ctx.find_object(SetList) print(users_context.api.users_sets_delete(user_token=users_context.token, set_num=set_num)) @@ -614,11 +706,12 @@ def users_sets_list(users_context): print(users_context.api.users_sets_list(user_token=users_context.token)) -@users_sets.command(name='read') +@users_sets.command(cls=TypedResult, type=SetListSet, invoke_without_command=True, name='read') @pass_userscontext +@click.pass_context @click.argument('set_num') -def users_sets_read(users_context, set_num): - print(users_context.api.users_sets_read(user_token=users_context.token, set_num=set_num)) +def users_sets_read(ctx, users_context, set_num): + GET(ctx, lambda: users_context.api.users_sets_read(user_token=users_context.token, set_num=set_num)) @users_sets.group(name='sync') diff --git a/patch_swagger.py b/patch_swagger.py index 5a49507..63c17ef 100755 --- a/patch_swagger.py +++ b/patch_swagger.py @@ -165,6 +165,7 @@ def ref(cls): "quantity": Integer, "include_spares": Boolean, "set": ref('Set'), + "set_num": String }, 'PartCategory': { "id": Integer, @@ -259,6 +260,16 @@ def ref(cls): } } + api['definitions'].update( + { + 'ErrorMessage': { + "type": "array", + 'items': { + 'type': 'string' + } + } + }) + for cls in classes: api['definitions'].update(get_typedef_array(cls)) api['definitions'].update(get_typedef(cls, classes[cls])) @@ -309,12 +320,13 @@ def set_schema(url, schema, code='200', method='get'): set_schema('/api/v3/lego/sets/{set_num}/parts/', ref('ArrayOfParts')) set_schema('/api/v3/lego/sets/{set_num}/sets/', ref('ArrayOfSets')) set_schema('/api/v3/lego/sets/{set_num}/alternates/', ref('ArrayOfMocs')) - set_schema('/api/v3/users/{user_token}/sets/', ref('ArrayOfSets')) + set_schema('/api/v3/users/{user_token}/sets/', ref('ArrayOfSetListSets')) set_schema('/api/v3/users/{user_token}/allparts/', ref('ArrayOfAllParts')) set_schema('/api/v3/users/{user_token}/lost_parts/', ref('ArrayOfParts')) set_schema('/api/v3/users/{user_token}/lost_parts/', ref('ArrayOfParts')) set_schema('/api/v3/users/{user_token}/lost_parts/', ref('ArrayOfLostParts')) set_schema('/api/v3/users/{user_token}/parts/', ref('ArrayOfPartListParts')) + set_schema('/api/v3/users/{user_token}/sets/', ref('SetListSet'), '201', 'post') # TODO # '/api/v3/users/{user_token}/lost_parts/', 'POST', From 668bd24f08b6d7779be4fef7ea35258122fc6ce1 Mon Sep 17 00:00:00 2001 From: rienafairefr Date: Thu, 6 Sep 2018 20:35:14 +0200 Subject: [PATCH 06/19] cli unit tests and fixes --- cli/__init__.py | 0 cli/rebrickable_cli/cli.py | 750 ---------------------------- cli/rebrickable_cli/cli/__init__.py | 0 cli/rebrickable_cli/cli/common.py | 82 +++ cli/rebrickable_cli/cli/lego.py | 175 +++++++ cli/rebrickable_cli/cli/main.py | 87 ++++ cli/rebrickable_cli/cli/user.py | 433 ++++++++++++++++ cli/rebrickable_cli/cli/users.py | 61 +++ cli/rebrickable_cli/utils.py | 50 +- cli/setup.py | 10 +- dev-requirements.txt | 2 + patch_swagger.py | 57 ++- tests/conftest.py | 43 ++ tests/test_cli.py | 398 +++++++-------- tests/test_cli_integration.py | 387 ++++++++++++++ tests/test_cli_utils.py | 34 +- tests/test_models_integration.py | 93 ++++ 17 files changed, 1650 insertions(+), 1012 deletions(-) create mode 100644 cli/__init__.py delete mode 100644 cli/rebrickable_cli/cli.py create mode 100644 cli/rebrickable_cli/cli/__init__.py create mode 100644 cli/rebrickable_cli/cli/common.py create mode 100644 cli/rebrickable_cli/cli/lego.py create mode 100644 cli/rebrickable_cli/cli/main.py create mode 100644 cli/rebrickable_cli/cli/user.py create mode 100644 cli/rebrickable_cli/cli/users.py create mode 100644 tests/conftest.py create mode 100644 tests/test_cli_integration.py create mode 100644 tests/test_models_integration.py diff --git a/cli/__init__.py b/cli/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cli/rebrickable_cli/cli.py b/cli/rebrickable_cli/cli.py deleted file mode 100644 index fb09369..0000000 --- a/cli/rebrickable_cli/cli.py +++ /dev/null @@ -1,750 +0,0 @@ -# -*- coding: utf-8 -*- - -"""Console script for pyrebrickable.""" -from getpass import getpass - -import click -from click import Abort, ClickException -from six.moves import input - -from rebrickable_api import ApiClient, Configuration, Color, Element, Moc, PartCategory, Part, PartColorsElement, Set, \ - Theme, Badge, Build, PartListPart, PartList, Profile, SetList, SetListSet -from rebrickable_api import LegoApi, UsersApi -from rebrickable_api.rest import ApiException -from rebrickable_cli.utils import update_data, get_data, DATA_PATH - - -class UsersContext(object): - def __init__(self, api, token): - self.api = api - self.token = token - self.setlist = None - - -pass_client = click.make_pass_decorator(ApiClient) -pass_legoapi = click.make_pass_decorator(LegoApi) -pass_userscontext = click.make_pass_decorator(UsersContext) -pass_usersapi = click.make_pass_decorator(UsersApi) - -def GET(ctx, fun): - current_obj = fun() - if ctx.invoked_subcommand is None: - print(current_obj) - else: - ctx.obj = current_obj - - -class TypedResult(click.Group): - def __init__(self, *args, **kwargs): - self.type_ = kwargs.pop('type', None) - super(TypedResult, self).__init__(*args, **kwargs) - for attribute_name, attribute_type in self.type_.openapi_types.items(): - def get_type_cmd(this): - @click.command() - @click.make_pass_decorator(this.type_) - def type_cmd(obj): - print(getattr(obj, attribute_name)) - - return type_cmd - - self.add_command(get_type_cmd(self), name=attribute_name) - - -def get_api_client(): - configuration = Configuration() - data = get_data() - api_key = data['api_key'] - configuration.api_key['Authorization'] = api_key - configuration.api_key_prefix['Authorization'] = 'key' - return ApiClient(configuration) - - -@click.group(help="Rebrickable CLI implemented in Python") -@click.pass_context -def main(ctx, args=None): - """Console script for pyrebrickable.""" - - try: - ctx.obj = get_api_client() - except (IOError, KeyError, ValueError): - if ctx.invoked_subcommand != 'register': - print('please register your API key using: \nrebrickable register') - raise click.Abort() - - -@main.command(help='registers an API key with the CLI') -def register(): - key = getpass(prompt='Please enter your API key:') - update_data('api_key', key) - print('OK, registered API key in %s' % DATA_PATH) - - -@main.group() -@pass_client -@click.pass_context -def lego(ctx, client): - ctx.obj = LegoApi(client) - - -def get_users_context(client): - users_api = UsersApi(client) - data = get_data() - users_token = data['users_token'] - return UsersContext(users_api, users_token) - - -@main.group() -@pass_client -@click.pass_context -def users(ctx, client): - users_api = UsersApi(client) - ctx.obj = users_api - try: - ctx.obj = get_users_context(client) - except (IOError, KeyError, ValueError): - if ctx.invoked_subcommand != 'login': - print('Please login using: \nrebrickable users login') - raise click.Abort() - - -@users.command(name='login') -@pass_usersapi -@click.argument('username', required=False) -def users_login(users_api, username=None): - if username is None: - username = input('Username: ') - password = getpass() - try: - users_token = users_api.users_token_create(username, password) - update_data('users_token', users_token.user_token) - - print('OK, saved users token into %s' % DATA_PATH) - except ApiException as e: - print('Login failed, response was %s' % e.body) - raise click.Abort() - - -@lego.group(name='parts') -def lego_parts(): - pass - - -@lego_parts.group(name='colors') -def lego_parts_colors(): - pass - - -@lego_parts_colors.group(name='sets') -def lego_parts_colors_sets(): - pass - - -@lego_parts_colors_sets.command(name='list') -@pass_legoapi -@click.argument('color_id') -@click.argument('set_num') -def lego_parts_colors_sets_list(api, color_id, set_num): - print(api.lego_parts_colors_sets_list(color_id=color_id, set_num=set_num)) - - -@lego.command(name='colors') -@pass_legoapi -def lego_colors_list(api): - print(api.lego_colors_list()) - - -@lego.group(cls=TypedResult, type=Color, invoke_without_command=True, name='color') -@pass_legoapi -@click.pass_context -@click.argument('id') -def lego_colors_read(ctx, api, id): - GET(ctx, lambda: api.lego_colors_read(id=id)) - - -@lego.command(cls=TypedResult, type=Element, invoke_without_command=True, name='element') -@pass_legoapi -@click.pass_context -@click.argument('element_id') -def lego_elements_read(ctx, api, element_id): - GET(ctx, lambda: api.lego_elements_read(element_id=element_id)) - - -@lego.group(name='mocs') -def lego_mocs(): - pass - - -@lego_mocs.group(name='parts') -def lego_mocs_parts(): - pass - - -@lego_mocs_parts.command(name='list') -@pass_legoapi -@click.argument('set_num') -def lego_mocs_parts_list(api, set_num): - print(api.lego_mocs_parts_list(set_num=set_num)) - - -@lego_mocs.command(cls=TypedResult, type=Moc, invoke_without_command=True, name='read') -@pass_legoapi -@click.pass_context -@click.argument('set_num') -def lego_mocs_read(ctx, api, set_num): - GET(ctx, lambda: api.lego_mocs_read(set_num=set_num)) - - -@lego.command(name='part_categories') -@pass_legoapi -def lego_part_categories_list(api): - print(api.lego_part_categories_list()) - - -@lego.command(cls=TypedResult, type=PartCategory, invoke_without_command=True, name='part_category') -@pass_legoapi -@click.pass_context -@click.argument('id') -def lego_part_categories_read(ctx, api, id): - GET(ctx, lambda: api.lego_part_categories_read(id=id)) - - -@lego_parts_colors.command(name='list') -@pass_legoapi -@click.argument('part_num') -def lego_parts_colors_list(api, part_num): - print(api.lego_parts_colors_list(part_num=part_num)) - - -@lego_parts_colors.group(cls=TypedResult, type=PartColorsElement, invoke_without_command=True, name='read') -@pass_legoapi -@click.pass_context -@click.argument('color_id') -@click.argument('part_num') -def lego_parts_colors_read(ctx, api, color_id, part_num): - GET(ctx, lambda: api.lego_parts_colors_read(color_id=color_id, part_num=part_num)) - - -@lego_parts_colors_sets.command(name='list') -@pass_legoapi -@click.argument('color_id') -@click.argument('part_num') -def lego_parts_colors_sets_list(api, color_id, part_num): - print(api.lego_parts_colors_sets_list(color_id=color_id, part_num=part_num)) - - -@lego_parts.command(name='list') -@pass_legoapi -def lego_parts_list(api): - print(api.lego_parts_list()) - - -@lego.command(cls=TypedResult, type=Part, invoke_without_command=True, name='part') -@pass_legoapi -@click.pass_context -@click.argument('part_num') -def lego_parts_read(ctx, api, part_num): - GET(ctx, lambda: api.lego_parts_read(part_num=part_num)) - - -@lego.group(name='sets') -def lego_sets(): - pass - - -@lego_sets.group(name='alternates') -def lego_sets_alternates(): - pass - - -@lego_sets_alternates.command(name='list') -@pass_legoapi -@click.argument('set_num') -def lego_sets_alternates_list(api, set_num): - print(api.lego_sets_alternates_list(set_num=set_num)) - - -@lego_sets.command(name='list') -@pass_legoapi -def lego_sets_list(api): - print(api.lego_sets_list()) - - -@lego_sets.group(name='parts') -def lego_sets_parts(): - pass - - -@lego_sets_parts.command(name='list') -@pass_legoapi -@click.argument('set_num') -def lego_sets_parts_list(api, set_num): - print(api.lego_sets_parts_list(set_num=set_num)) - - -@lego.command(cls=TypedResult, type=Set, invoke_without_command=True, name='set') -@pass_legoapi -@click.pass_context -@click.argument('set_num') -def lego_sets_read(ctx, api, set_num): - GET(ctx, lambda: api.lego_sets_read(set_num=set_num)) - - -@lego_sets.group(name='sets') -def lego_sets_sets(): - pass - - -@lego_sets_sets.command(name='list') -@pass_legoapi -@click.argument('set_num') -def lego_sets_sets_list(api, set_num): - print(api.lego_sets_sets_list(set_num=set_num)) - - -@lego.command(name='themes') -@pass_legoapi -def lego_themes_list(api): - print(api.lego_themes_list()) - - -@lego.command(cls=TypedResult, type=Theme, invoke_without_command=True, name='theme') -@pass_legoapi -@click.pass_context -@click.argument('id') -def lego_themes_read(ctx, api, id): - GET(ctx, lambda: api.lego_themes_read(id=id)) - - -@users.group(name='allparts') -def users_allparts(): - pass - - -@users_allparts.command(name='list') -@pass_userscontext -def users_allparts_list(users_context): - print(users_context.api.users_allparts_list(user_token=users_context.token)) - - -@users.command(name='badges') -@pass_userscontext -def users_badges_list(users_context): - print(users_context.api.users_badges_list()) - - -@users.command(cls=TypedResult, type=Badge, invoke_without_command=True, name='badge') -@pass_userscontext -@click.pass_context -@click.argument('id') -def users_badges_read(ctx, users_context, id): - GET(ctx, lambda: users_context.api.users_badges_read(id=id)) - - -@users.command(cls=TypedResult, type=Build, invoke_without_command=True, name='build') -@pass_userscontext -@click.pass_context -@click.argument('set_num') -def users_build_read(ctx, users_context, set_num): - GET(ctx, lambda: users_context.api.users_build_read(user_token=users_context.token, - set_num=set_num)) - - -@users.group(name='lost_parts') -def users_lost_parts(): - pass - - -@users_lost_parts.command(name='create') -@pass_userscontext -@click.argument('inv_part_id') -def users_lost_parts_create(users_context, inv_part_id): - print(users_context.api.users_lost_parts_create(user_token=users_context.token, inv_part_id=inv_part_id)) - - -@users_lost_parts.command(name='delete') -@pass_userscontext -@click.argument('id') -def users_lost_parts_delete(users_context, id): - print(users_context.api.users_lost_parts_delete(user_token=users_context.token, id=id)) - - -@users_lost_parts.command(name='list') -@pass_userscontext -def users_lost_parts_list(users_context): - print(users_context.api.users_lost_parts_list(user_token=users_context.token)) - - -@users.group(name='partlists') -def users_partlists(): - pass - - -@users_partlists.command(name='create') -@pass_userscontext -@click.argument('name') -def users_partlists_create(users_context, name): - print(users_context.api.users_partlists_create(user_token=users_context.token, - name=name)) - - -@users_partlists.command(name='delete') -@pass_userscontext -@click.argument('list_id') -def users_partlists_delete(users_context, list_id): - print(users_context.api.users_partlists_delete(user_token=users_context.token, - list_id=list_id)) - - -@users_partlists.command(name='list') -@pass_userscontext -def users_partlists_list(users_context): - print(users_context.api.users_partlists_list(user_token=users_context.token)) - - -@users_partlists.group(name='partial') -def users_partlists_partial(): - pass - - -@users_partlists_partial.command(name='update') -@pass_userscontext -@click.argument('list_id') -def users_partlists_partial_update(users_context, list_id): - print(users_context.api.users_partlists_partial_update(user_token=users_context.token, - list_id=list_id)) - - -@users_partlists.group(name='parts') -def users_partlists_parts(): - pass - - -@users_partlists_parts.command(name='create') -@pass_userscontext -@click.argument('list_id') -@click.argument('part_num') -@click.argument('quantity') -@click.argument('color_id') -def users_partlists_parts_create(users_context, list_id, part_num, quantity, color_id): - print(users_context.api.users_partlists_parts_create(user_token=users_context.token, - list_id=list_id, - part_num=part_num, - quantity=quantity, - color_id=color_id)) - - -@users_partlists_parts.command(name='delete') -@pass_userscontext -@click.argument('color_id') -@click.argument('list_id') -@click.argument('part_num') -def users_partlists_parts_delete(users_context, color_id, list_id, part_num): - print(users_context.api.users_partlists_parts_delete(user_token=users_context.token, - color_id=color_id, - list_id=list_id, - part_num=part_num)) - - -@users_partlists_parts.command(name='list') -@pass_userscontext -@click.argument('list_id') -def users_partlists_parts_list(users_context, list_id): - print(users_context.api.users_partlists_parts_list(user_token=users_context.token, list_id=list_id)) - - -@users_partlists_parts.command(cls=TypedResult, type=PartListPart, invoke_without_command=True, name='read') -@pass_userscontext -@click.pass_context -@click.argument('color_id') -@click.argument('list_id') -@click.argument('part_num') -def users_partlists_parts_read(ctx, users_context, color_id, list_id, part_num): - GET(ctx, lambda: users_context.api.users_partlists_parts_read(user_token=users_context.token, color_id=color_id, - list_id=list_id, - part_num=part_num)) - - -@users_partlists_parts.command(name='update') -@pass_userscontext -@click.argument('color_id') -@click.argument('list_id') -@click.argument('part_num') -@click.argument('quantity') -def users_partlists_parts_update(users_context, color_id, list_id, part_num, quantity): - print(users_context.api.users_partlists_parts_update(user_token=users_context.token, color_id=color_id, - list_id=list_id, part_num=part_num, - quantity=quantity)) - - -@users_partlists.command(cls=TypedResult, type=PartList, invoke_without_command=True, name='read') -@pass_userscontext -@click.pass_context -@click.argument('list_id') -def users_partlists_read(ctx, users_context, list_id): - GET(ctx, lambda: users_context.api.users_partlists_read(users_context.token, list_id=list_id)) - - -@users_partlists.command(name='update') -@pass_userscontext -@click.argument('list_id') -@click.argument('name') -def users_partlists_update(users_context, list_id, name): - print(users_context.api.users_partlists_update(users_context.token, list_id=list_id, name=name)) - - -@users.command(name='parts') -@pass_userscontext -def users_parts_list(users_context): - print(users_context.api.users_parts_list(user_token=users_context.token)) - - -@users.group(cls=TypedResult, type=Profile, invoke_without_command=True, name='profile') -@pass_userscontext -@click.pass_context -def users_profile_get(ctx, users_context): - GET(ctx, lambda: users_context.api.users_profile_list(user_token=users_context.token)) - - -@users.group('setlists', invoke_without_command=True) -@pass_userscontext -@click.pass_context -def users_setlists(ctx, users_context): - if ctx.invoked_subcommand is None: - print(users_context.api.users_setlists_list(user_token=users_context.token)) - - -@users.group('setlist', cls=TypedResult, type=SetList, invoke_without_command=True) -@click.argument('list_id') -@pass_userscontext -@click.pass_context -def users_setlist(ctx, users_context, list_id): - setlist = users_context.api.users_setlists_read(user_token=users_context.token, list_id=list_id) - ctx.obj = setlist - if ctx.invoked_subcommand is None: - GET(ctx, lambda: users_context.api.users_setlists_read(user_token=users_context.token, list_id=setlist.id)) - - -@users_setlists.command(name='create') -@pass_userscontext -@click.argument('name') -def users_setlists_create(users_context, name): - print(users_context.api.users_setlists_create(user_token=users_context.token, name=name)) - - -def setlist_command(fun): - @pass_userscontext - def new_fun(users_context, *args, **kwargs): - setlist = users_context.setlist - if setlist is not None: - fun(*args, **kwargs) - else: - raise ClickException('need a list_id !') - return new_fun - - -@users_setlist.command(name='delete') -@pass_userscontext -@click.pass_context -def users_setlists_delete(ctx, users_context): - setlist = ctx.find_object(SetList) - print(users_context.api.users_setlists_delete(user_token=users_context.token, list_id=setlist.id)) - - -@users_setlist.group(name='partial') -def users_setlists_partial(): - pass - - -@users_setlist.command(name='update') -@pass_userscontext -@click.pass_context -def users_setlists_partial_update(ctx, users_context): - setlist = ctx.find_object(SetList) - print(users_context.api.users_setlists_partial_update(user_token=users_context.token, list_id=setlist.id)) - - -@users_setlist.group(name='sets', invoke_without_command=True) -@pass_userscontext -@click.pass_context -def users_setlists_sets(ctx, users_context): - setlist = ctx.find_object(SetList) - if ctx.invoked_subcommand is None: - print(users_context.api.users_setlists_sets_list(user_token=users_context.token, list_id=setlist.id)) - - -@users_setlist.group(name='set', cls=TypedResult, type=SetListSet, invoke_without_command=True) -@pass_userscontext -@click.pass_context -@click.argument('set_num') -def users_setlists_sets(ctx, users_context, set_num): - setlist = ctx.find_object(SetList) - if ctx.invoked_subcommand is None: - setlistset = users_context.api.users_setlists_sets_read(user_token=users_context.token, list_id=setlist.id, set_num=set_num) - ctx.obj = setlistset - GET(ctx, lambda: setlistset) - - -@users_setlists_sets.command(name='create') -@pass_userscontext -@click.pass_context -@click.argument('set_num') -def users_setlists_sets_create(ctx, users_context, set_num): - setlist = ctx.find_object(SetList) - print(users_context.api.users_setlists_sets_create(user_token=users_context.token, - list_id=setlist.id, - set_num=set_num)) - - -@users_setlists_sets.command(name='delete') -@pass_userscontext -@click.pass_context - -def users_setlists_sets_delete(ctx, users_context, set_num): - setlist = ctx.find_object(SetList) - print(users_context.api.users_setlists_sets_delete(user_token=users_context.token, - list_id=setlist.id, - set_num=set_num)) - - -@users_setlists_sets.group() -def users_setlists_sets_partial(): - pass - - -@users_setlists_sets_partial.command(name='update') -@pass_userscontext -@click.pass_context -@click.argument('set_num') -def users_setlists_sets_partial_update(ctx, users_context, set_num): - setlist = ctx.find_object(SetList) - print(users_context.api.users_setlists_sets_partial_update(user_token=users_context.token, - list_id=setlist.id, - set_num=set_num)) - - -@users_setlists_sets.command(cls=TypedResult, type=SetListSet, invoke_without_command=True, name='read') -@pass_userscontext -@click.pass_context -@click.argument('set_num') -def users_setlists_sets_read(ctx, users_context, set_num): - setlist = ctx.find_object(SetList) - GET(ctx, lambda: users_context.api.users_setlists_sets_read(user_token=users_context.token, - list_id=setlist.id, - set_num=set_num)) - - -@users_setlists_sets.command(name='update') -@pass_userscontext -@click.pass_context -@click.argument('set_num') -def users_setlists_sets_update(ctx, users_context, set_num): - setlist = ctx.find_object(SetList) - print(users_context.api.users_setlists_sets_update(user_token=users_context.token, - list_id=setlist.id, - set_num=set_num)) - - -@users_setlists.command(name='update') -@pass_userscontext -@click.pass_context -@click.argument('name') -def users_setlists_update(ctx, users_context, name): - setlist = ctx.find_object(SetList) - print(users_context.api.users_setlists_update(user_token=users_context.token, - list_id=setlist.id, - name=name)) - - -@users.group(name='sets', invoke_without_command=True) -@pass_userscontext -@click.pass_context -@click.option('--set_num', expose_value=False) -@click.option('--theme_id', expose_value=False) -@click.option('--min_year', expose_value=False) -@click.option('--max_year', expose_value=False) -@click.option('--min_parts', expose_value=False) -@click.option('--max_parts', expose_value=False) -@click.option('--search', expose_value=False) -def users_sets(ctx, users_context, *args, **kwargs): - if ctx.invoked_subcommand is None: - print(users_context.api.users_sets_list(users_context.token, *args, **kwargs)) - - -@users.group(name='set', cls=TypedResult, type=SetListSet, invoke_without_command=True) -@pass_userscontext -@click.pass_context -@click.argument('set_num') -def users_set(ctx, users_context, set_num): - set = users_context.api.users_sets_read(user_token=users_context.token, set_num=set_num) - ctx.obj = set - if ctx.invoked_subcommand is None: - GET(ctx, lambda: set) - - -@users_sets.command(name='create') -@pass_userscontext -@click.argument('set_num') -def users_sets_create(users_context, set_num): - try: - print(users_context.api.users_sets_create(user_token=users_context.token, - set_num=set_num)) - except ApiException, e: - print('an error occured: %s, %s, %s' % (e.status, e.body, e.message)) - - -@users_set.command(name='delete') -@pass_userscontext -@click.pass_context -def users_sets_delete(ctx, users_context): - setlistset = ctx.find_object(SetList) - print(users_context.api.users_sets_delete(user_token=users_context.token, set_num=set_num)) - - -@users_sets.command(name='list') -@pass_userscontext -def users_sets_list(users_context): - print(users_context.api.users_sets_list(user_token=users_context.token)) - - -@users_sets.command(cls=TypedResult, type=SetListSet, invoke_without_command=True, name='read') -@pass_userscontext -@click.pass_context -@click.argument('set_num') -def users_sets_read(ctx, users_context, set_num): - GET(ctx, lambda: users_context.api.users_sets_read(user_token=users_context.token, set_num=set_num)) - - -@users_sets.group(name='sync') -def users_sets_sync(): - pass - - -@users_sets_sync.command(name='create') -@pass_userscontext -@click.argument('set_num') -def users_sets_sync_create(users_context, set_num): - print(users_context.api.users_sets_sync_create(user_token=users_context.token, set_num=set_num)) - - -@users_sets_sync.command(name='update') -@pass_userscontext -@click.argument('set_num') -def users_sets_update(users_context, set_num): - print(users_context.api.users_sets_update(user_token=users_context.token, set_num=set_num)) - - -@users.group(name='token') -def users_token(): - pass - - -@users_token.command(name='create') -@pass_userscontext -@click.argument('username') -@click.argument('password') -def users_token_create(users_context, username, password): - print(users_context.api.users_token_create(username=username, password=password)) - - -if __name__ == "__main__": - main() diff --git a/cli/rebrickable_cli/cli/__init__.py b/cli/rebrickable_cli/cli/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/cli/rebrickable_cli/cli/common.py b/cli/rebrickable_cli/cli/common.py new file mode 100644 index 0000000..80aae21 --- /dev/null +++ b/cli/rebrickable_cli/cli/common.py @@ -0,0 +1,82 @@ +from functools import wraps + +import click +from click import get_current_context + +from rebrickable_api import UsersApi, LegoApi +from rebrickable_cli.utils import get_data + + +class UserContext(object): + def __init__(self, api, token): + self.api = api + self.token = token + self.setlist = None + + +def oprint(obj): + # print an object using the current configured output (json/yaml/py) + get_current_context().find_object(GlobalContext).format.output(obj) + + +class GlobalContext(object): + def __init__(self, format, client): + self.format = format + self.client = client + + + +def get_or_push_context_obj(fun): + @click.pass_context + @wraps(fun) + def decorated(ctx, *args, **kwargs): + try: + current_obj = fun(ctx, *args, **kwargs) + except: + current_obj = fun(*args, **kwargs) + if ctx.invoked_subcommand is None: + oprint(current_obj) + else: + ctx.obj = current_obj + return current_obj + + return decorated + + +def object_print(fun): + def decorated(*args, **kwargs): + obj = fun(*args, **kwargs) + oprint(obj) + + return decorated + + +def add_typed_subcommands(type_): + def add_fun(fun, attribute_name): + @fun.command(name=attribute_name) + @click.make_pass_decorator(type_) + def type_cmd(obj): + print(getattr(obj, attribute_name)) + + def decorator(fun): + for attribute_name, attribute_type in type_.openapi_types.items(): + add_fun(fun, attribute_name) + + setattr(fun, 'invoke_without_command', True) + + return fun + + return decorator + + +def get_user_context(client, username='%%default%%'): + users_api = UsersApi(client) + data = get_data() + user_token = data['users'][username]['token'] + return UserContext(users_api, user_token) + + +pass_global = click.make_pass_decorator(GlobalContext) +pass_legoapi = click.make_pass_decorator(LegoApi) +pass_usercontext = click.make_pass_decorator(UserContext) +pass_usersapi = click.make_pass_decorator(UsersApi) \ No newline at end of file diff --git a/cli/rebrickable_cli/cli/lego.py b/cli/rebrickable_cli/cli/lego.py new file mode 100644 index 0000000..e321c50 --- /dev/null +++ b/cli/rebrickable_cli/cli/lego.py @@ -0,0 +1,175 @@ +import click + +from rebrickable_api import LegoApi, Part, PartColorsElement, Color, Element, Moc, PartCategory, Set, Theme +from rebrickable_cli.cli.common import pass_global, add_typed_subcommands, pass_legoapi, get_or_push_context_obj, \ + object_print, oprint + + +@click.group(help='LEGO data (parts, sets, themes, etc.)') +@pass_global +@click.pass_context +def lego(ctx, global_context): + ctx.obj = LegoApi(global_context.client) + + +@lego.command('parts') +@pass_legoapi +@object_print +def lego_parts(api): + return api.lego_parts_list() + + +@add_typed_subcommands(Part) +@lego.group('part') +@pass_legoapi +@click.argument('part_num') +@get_or_push_context_obj +def lego_part(api, part_num): + return api.lego_parts_read(part_num=part_num) + + +@lego_part.command('colors') +@pass_legoapi +@click.pass_context +@object_print +def lego_part_colors(ctx, api): + part = ctx.find_object(Part) + return api.lego_parts_colors_list(part_num=part.part_num) + + +@add_typed_subcommands(PartColorsElement) +@lego_part.group('color') +@pass_legoapi +@click.pass_context +@click.argument('color_id', type=int) +@get_or_push_context_obj +def lego_part_color(ctx, api, color_id): + part = ctx.find_object(Part) + return api.lego_parts_colors_read(color_id=color_id, part_num=part.part_num) + + +@lego_part_color.command('sets') +@pass_legoapi +@click.pass_context +@object_print +def lego_part_color_sets(ctx, api): + color = ctx.find_object(Color) + part = ctx.find_object(Part) + return api.lego_parts_colors_sets_list(color_id=color.id, part_num=part.part_num) + + +@lego.command('colors') +@pass_legoapi +@object_print +def lego_colors(api): + return api.lego_colors_list() + + +@add_typed_subcommands(Color) +@lego.group('color') +@pass_legoapi +@click.argument('color_id', type=int) +@get_or_push_context_obj +def lego_color(api, color_id): + return api.lego_colors_read(id=color_id) + + +@add_typed_subcommands(Element) +@lego.group('element') +@pass_legoapi +@click.argument('element_id') +@get_or_push_context_obj +def lego_element(api, element_id): + return api.lego_elements_read(element_id=element_id) + + +@add_typed_subcommands(Moc) +@lego.group('moc') +@pass_legoapi +@click.argument('set_num') +@get_or_push_context_obj +def lego_moc(api, set_num): + return api.lego_mocs_read(set_num=set_num) + + +@lego_moc.command('parts') +@pass_legoapi +@click.pass_context +@object_print +def lego_moc_parts(ctx, api): + moc = ctx.find_object(Moc) + return api.lego_mocs_parts_list(set_num=moc.set_num) + + +@lego.command('part_categories') +@pass_legoapi +@object_print +def lego_part_categories(api): + return api.lego_part_categories_list() + + +@add_typed_subcommands(PartCategory) +@lego.group('part_category') +@pass_legoapi +@click.argument('id', type=int) +@object_print +def lego_part_category(api, id): + return api.lego_part_categories_read(id=id) + + +@lego.command('sets') +@pass_legoapi +def lego_sets(api): + oprint(api.lego_sets_list()) + + +@add_typed_subcommands(Set) +@lego.group('set') +@pass_legoapi +@click.argument('set_num') +@get_or_push_context_obj +def lego_set(api, set_num): + return api.lego_sets_read(set_num=set_num) + + +@lego_set.command('parts') +@pass_legoapi +@click.pass_context +@object_print +def lego_set_parts(ctx, api): + set = ctx.find_object(Set) + return api.lego_sets_parts_list(set_num=set.set_num) + + +@lego_set.command('alternates') +@pass_legoapi +@click.pass_context +@object_print +def lego_set_alternates(ctx, api): + set = ctx.find_object(Set) + return api.lego_sets_alternates_list(set_num=set.set_num) + + +@lego_set.command('sets') +@pass_legoapi +@click.pass_context +@object_print +def lego_set_sets(ctx, api): + set = ctx.find_object(Set) + return api.lego_sets_sets_list(set_num=set.set_num) + + +@lego.command('themes') +@pass_legoapi +@object_print +def lego_themes(api): + return api.lego_themes_list() + + +@add_typed_subcommands(Theme) +@lego.group('theme') +@pass_legoapi +@click.argument('theme_id') +@get_or_push_context_obj +def lego_theme(api, theme_id): + return api.lego_themes_read(id=theme_id) \ No newline at end of file diff --git a/cli/rebrickable_cli/cli/main.py b/cli/rebrickable_cli/cli/main.py new file mode 100644 index 0000000..daecf98 --- /dev/null +++ b/cli/rebrickable_cli/cli/main.py @@ -0,0 +1,87 @@ +# -*- coding: utf-8 -*- + +"""Console script for pyrebrickable.""" +from __future__ import print_function +import json +from collections import namedtuple +from getpass import getpass + +import click +import yaml +from click import get_current_context + +from rebrickable_api import ApiClient, Configuration +from rebrickable_cli.cli.common import GlobalContext + +from rebrickable_cli.cli.lego import lego +from rebrickable_cli.cli.user import user +from rebrickable_cli.cli.users import users + +try: + from enum import Enum, EnumMeta # pragma: no cover +except ImportError: # pragma: no cover + from enum34 import Enum, EnumMeta # pragma: no cover + +from rebrickable_cli.utils import get_data, DATA_PATH, EnumType, write_data + + +class OutputFormat(Enum): + json = 0 # json.dumps + yaml = 1 # yaml.dump + py = 2 # print + + + +OutputFormatter = namedtuple('OutputFormatter', ['output']) + + +def get_api_client(): + configuration = Configuration() + data = get_data() + api_key = data['api_key'] + configuration.api_key['Authorization'] = api_key + configuration.api_key_prefix['Authorization'] = 'key' + return ApiClient(configuration) + + +@click.group(help="Rebrickable CLI implemented in Python") +@click.pass_context +@click.option('--output', '-o', type=EnumType(OutputFormat, casesensitive=False), default="py") +def main(ctx, output): + """Console script for pyrebrickable.""" + + format = None + if output == OutputFormat.json: + format = OutputFormatter(output=lambda o: print(json.dumps(o.to_dict(), default=str))) + elif output == OutputFormat.yaml: + format = OutputFormatter(output=lambda o: print(yaml.dump(o.to_dict(), default_flow_style=False))) + elif output == OutputFormat.py: + format = OutputFormatter(output=lambda o: print(o)) + + try: + ctx.obj = GlobalContext(format, get_api_client()) + except (IOError, KeyError, ValueError): + if ctx.invoked_subcommand != 'register': + print('please register your API key using: \nrebrickable register') + raise click.Abort() + + +def get_api_key(): + return getpass(prompt='Please enter your API key:') + + +@main.command(help='registers an API key with the CLI') +def register(): + key = get_api_key() + data = get_data() + data['api_key'] = key + write_data(data) + print('OK, registered API key in %s' % DATA_PATH) + + +main.add_command(lego) +main.add_command(users) +main.add_command(user) + +if __name__ == "__main__": + main() diff --git a/cli/rebrickable_cli/cli/user.py b/cli/rebrickable_cli/cli/user.py new file mode 100644 index 0000000..4caf8e0 --- /dev/null +++ b/cli/rebrickable_cli/cli/user.py @@ -0,0 +1,433 @@ +import json + +import click + +from rebrickable_api import PartList, PartListPart, Profile, SetList, SetListSet, Set, Build +from rebrickable_api.rest import ApiException +from rebrickable_cli.cli.common import pass_global, get_user_context, add_typed_subcommands, pass_usercontext, \ + get_or_push_context_obj, object_print + + +@click.group(help='user data (sets, parts lists, set lists, etc.)') +@click.option('--username', '-u', required=False, default='%%default%%') +@pass_global +@click.pass_context +def user(ctx, global_context, username): + try: + ctx.obj = get_user_context(global_context.client, username) + except (IOError, KeyError, ValueError): + print('Please login using: \nrebrickable users login [-u username]') + raise click.Abort() + + +@add_typed_subcommands(PartList) +@user.group('partlist') +@click.argument('list_id', type=int) +@pass_usercontext +@get_or_push_context_obj +def user_partlist(user_context, list_id): + return user_context.api.users_partlists_read(user_token=user_context.token, list_id=list_id) + + +@user_partlist.command('delete') +@pass_usercontext +@click.pass_context +@object_print +def user_partlist_delete(ctx, user_context): + partlist = ctx.find_object(PartList) + return user_context.api.users_partlists_delete(user_token=user_context.token, + list_id=partlist.id) + + +@user_partlist.command('partial_update') +@pass_usercontext +@click.pass_context +@click.option('--name', expose_value=False) +@click.option('--is_buildable', expose_value=False, type=bool) +@click.option('--num_parts', expose_value=False, type=int) +@object_print +def user_partlist_partial_update(ctx, user_context, *args, **kwargs): + partlist = ctx.find_object(PartList) + return user_context.api.users_partlists_partial_update(user_token=user_context.token, + list_id=partlist.id, *args, **kwargs) + + +@user_partlist.group('parts') +def user_partlist_parts(): + pass + + +@user_partlist_parts.command('create') +@pass_usercontext +@click.pass_context +@click.argument('part_num') +@click.argument('quantity', type=int) +@click.argument('color_id', type=int) +@object_print +def user_partlist_parts_create(ctx, user_context, part_num, quantity, color_id): + partlist = ctx.find_object(PartList) + return user_context.api.users_partlists_parts_create(user_token=user_context.token, + list_id=partlist.id, + part_num=part_num, + quantity=quantity, + color_id=color_id) + + +@user_partlist_parts.command('delete') +@pass_usercontext +@click.pass_context +@click.argument('color_id', type=int) +@click.argument('part_num') +@object_print +def user_partlist_parts_delete(ctx, user_context, color_id, part_num): + partlist = ctx.find_object(PartList) + return user_context.api.users_partlists_parts_delete(user_token=user_context.token, + color_id=color_id, + list_id=partlist.id, + part_num=part_num) + + +@user_partlist_parts.command('list') +@pass_usercontext +@click.pass_context +@object_print +def user_partlist_parts_list(ctx, user_context): + partlist = ctx.find_object(PartList) + return user_context.api.users_partlists_parts_list(user_token=user_context.token, list_id=partlist.id) + + +@add_typed_subcommands(PartList) +@user_partlist.group('part') +@pass_usercontext +@click.pass_context +@click.argument('color_id', type=int) +@click.argument('part_num') +@get_or_push_context_obj +def user_partlist_part(ctx, user_context, color_id, part_num): + partlist = ctx.find_object(PartList) + return user_context.api.users_partlists_parts_read(user_token=user_context.token, color_id=color_id, + list_id=partlist.id, + part_num=part_num) + + +@user_partlist_part.command('update') +@pass_usercontext +@click.pass_context +@click.argument('quantity', type=int) +@object_print +def user_partlist_part_update(ctx, user_context, quantity): + partlist = ctx.find_object(PartList) + partlist_part = ctx.find_object(PartListPart) + return user_context.api.users_partlists_parts_update(user_token=user_context.token, color_id=partlist_part.color.id, + list_id=partlist.id, part_num=partlist_part.part.part_num, + quantity=quantity) + + +@user_partlist.command('update') +@pass_usercontext +@click.pass_context +@click.argument('name') +@object_print +def user_partlist_update(ctx, user_context, name): + partlist = ctx.find_object(PartList) + return user_context.api.users_partlists_update(user_token=user_context.token, list_id=partlist.id, name=name) + + +@user.command('parts') +@pass_usercontext +@object_print +def user_parts(user_context): + return user_context.api.users_parts_list(user_token=user_context.token) + + +@add_typed_subcommands(Profile) +@user.group('profile', invoke_without_command=True) +@pass_usercontext +@get_or_push_context_obj +def user_profile(user_context): + return user_context.api.users_profile_list(user_token=user_context.token) + + +@user.group('setlists') +def user_setlists(): + pass + + +@user_setlists.command('list') +@pass_usercontext +@object_print +def user_setlists_list(user_context): + return user_context.api.users_setlists_list(user_token=user_context.token) + + +@add_typed_subcommands(SetList) +@user.group('setlist') +@click.argument('list_id', type=int) +@pass_usercontext +@get_or_push_context_obj +def user_setlist(user_context, list_id): + return user_context.api.users_setlists_read(user_token=user_context.token, list_id=list_id) + + +@user_setlists.command('create') +@pass_usercontext +@click.argument('name') +@object_print +def user_setlists_create(user_context, name): + return user_context.api.users_setlists_create(user_token=user_context.token, name=name) + + +@user_setlist.command('delete') +@pass_usercontext +@click.pass_context +@object_print +def user_setlist_delete(ctx, user_context): + setlist = ctx.find_object(SetList) + return user_context.api.users_setlists_delete(user_token=user_context.token, list_id=setlist.id) + + +@user_setlist.group('partial') +def user_setlists_partial(): + pass + + +@user_setlist.command('update') +@pass_usercontext +@click.pass_context +@object_print +def user_setlist_partial_update(ctx, user_context): + setlist = ctx.find_object(SetList) + return user_context.api.users_setlists_partial_update(user_token=user_context.token, list_id=setlist.id) + + +@user_setlist.group('sets') +@pass_usercontext +def user_setlist_sets(ctx, user_context): + pass + + +@user_setlist_sets.command('list') +@pass_usercontext +@click.pass_context +@object_print +def user_setlist_sets_list(ctx, user_context): + setlist = ctx.find_object(SetList) + return user_context.api.users_setlists_sets_list(user_token=user_context.token, list_id=setlist.id) + + +@add_typed_subcommands(SetListSet) +@user_setlist.group('set') +@pass_usercontext +@click.pass_context +@click.argument('set_num') +@get_or_push_context_obj +def user_setlist_set(ctx, user_context, set_num): + setlist = ctx.find_object(SetList) + return user_context.api.users_setlists_sets_read(user_token=user_context.token, list_id=setlist.id, set_num=set_num) + + +@user_setlist_sets.command('create') +@pass_usercontext +@click.pass_context +@click.argument('set_num') +@object_print +def user_setlist_sets_create(ctx, user_context, set_num): + setlist = ctx.find_object(SetList) + return user_context.api.users_setlists_sets_create(user_token=user_context.token, + list_id=setlist.id, + set_num=set_num) + + +@user_setlist_sets.command('delete') +@pass_usercontext +@click.pass_context +@object_print +def user_setlist_set_delete(ctx, user_context): + setlist = ctx.find_object(SetList) + setlistset = ctx.find_object(SetListSet) + set_num = setlistset.set.set_num if setlistset.set else setlistset.set_num + return user_context.api.users_setlists_sets_delete(user_token=user_context.token, + list_id=setlist.id, + set_num=set_num) + + +@user_setlist_sets.group() +def user_setlists_sets_partial(): + pass + + +@user_setlists_sets_partial.command('update') +@pass_usercontext +@click.pass_context +@click.argument('set_num') +@object_print +def user_setlist_set_partial_update(ctx, user_context, set_num): + setlist = ctx.find_object(SetList) + return user_context.api.users_setlists_sets_partial_update(user_token=user_context.token, + list_id=setlist.id, + set_num=set_num) + + +@user_setlist_sets.command('update') +@pass_usercontext +@click.pass_context +@object_print +def user_setlist_set_update(ctx, user_context): + setlist = ctx.find_object(SetList) + setlistset = ctx.find_object(SetListSet) + set_num = setlistset.set.set_num if setlistset.set else setlistset.set_num + return user_context.api.users_setlists_sets_update(user_token=user_context.token, + list_id=setlist.id, + set_num=set_num) + + +@user_setlist.command('update') +@pass_usercontext +@click.pass_context +@click.argument('name') +@object_print +def user_setlist_update(ctx, user_context, name): + setlist = ctx.find_object(SetList) + return user_context.api.users_setlists_update(user_token=user_context.token, + list_id=setlist.id, + name=name) + + +@user.group('sets') +def user_sets(): + pass + + +@user_sets.command('list') +@pass_usercontext +@click.option('--set_num', expose_value=False) +@click.option('--theme_id', expose_value=False) +@click.option('--min_year', expose_value=False) +@click.option('--max_year', expose_value=False) +@click.option('--min_parts', expose_value=False) +@click.option('--max_parts', expose_value=False) +@click.option('--search', expose_value=False) +@object_print +def user_sets_list(user_context, *args, **kwargs): + return user_context.api.users_sets_list(user_token=user_context.token, *args, **kwargs) + + +@add_typed_subcommands(SetListSet) +@user.group('set') +@pass_usercontext +@click.argument('set_num') +@get_or_push_context_obj +def user_set(user_context, set_num): + return user_context.api.users_sets_read(user_token=user_context.token, set_num=set_num) + + +@user_sets.command('create') +@pass_usercontext +@click.argument('set_num') +@object_print +def user_sets_create(user_context, set_num): + try: + return user_context.api.users_sets_create(user_token=user_context.token, + set_num=set_num) + except ApiException as e: + print('an error occured: %s, %s, %s' % (e.status, e.body, e.message)) + + +@user_set.command('delete') +@pass_usercontext +@click.pass_context +@object_print +def user_set_delete(ctx, user_context): + set = ctx.find_object(Set) + try: + return user_context.api.users_sets_delete(user_token=user_context.token, set_num=set.set_num) + except ApiException as e: + print('an error occured: %s, %s, %s' % (e.status, e.body, e.message)) + + +@user_sets.command('sync') +@pass_usercontext +@click.option('--file', '-f', type=click.File('r'), default='-') +@object_print +def user_sets_sync(user_context, file): + # Assume the file contains a json list of SetListSet + file_content = file.read() + array_of_set_list_sets = json.loads(file_content) + return user_context.api.users_sets_sync_create( + user_token=user_context.token, array_of_set_list_sets=array_of_set_list_sets) + + +@user_set.command('sync') +@pass_usercontext +@click.pass_context +@object_print +def user_set_update(ctx, user_context): + set = ctx.find_object(Set) + return user_context.api.users_sets_update( + user_token=user_context.token, set_num=set.set_num) + + +@user.command('allparts') +@pass_usercontext +@object_print +def user_allparts(user_context): + return user_context.api.users_allparts_list(user_token=user_context.token) + + +@add_typed_subcommands(Build) +@user.group('build') +@pass_usercontext +@click.argument('set_num') +@get_or_push_context_obj +def user_build(user_context, set_num): + return user_context.api.users_build_read(user_token=user_context.token, + set_num=set_num) + + +@user.group('lost_parts') +def user_lost_parts(): + pass + + +@user_lost_parts.command('create') +@pass_usercontext +@click.argument('inv_part_id', type=int) +@object_print +def user_lost_parts_create(user_context, inv_part_id): + return user_context.api.users_lost_parts_create(user_token=user_context.token, inv_part_id=inv_part_id) + + +@user_lost_parts.command('delete') +@pass_usercontext +@click.argument('lost_part_id', type=int) +@object_print +def user_lost_parts_delete(user_context, lost_part_id): + return user_context.api.users_lost_parts_delete(user_token=user_context.token, id=lost_part_id) + + +@user_lost_parts.command('list') +@pass_usercontext +@object_print +def user_lost_parts_list(user_context): + return user_context.api.users_lost_parts_list(user_token=user_context.token) + + +@user.group('partlists') +def user_partlists(): + pass + + +@user_partlists.command('create') +@pass_usercontext +@click.argument('name') +@object_print +def user_partlists_create(user_context, name): + return user_context.api.users_partlists_create(user_token=user_context.token, + name=name) + + +@user_partlists.command('list') +@pass_usercontext +@object_print +def user_partlists_list(user_context): + return user_context.api.users_partlists_list(user_token=user_context.token) \ No newline at end of file diff --git a/cli/rebrickable_cli/cli/users.py b/cli/rebrickable_cli/cli/users.py new file mode 100644 index 0000000..4d95004 --- /dev/null +++ b/cli/rebrickable_cli/cli/users.py @@ -0,0 +1,61 @@ +from getpass import getpass + +import click + +from rebrickable_api import UsersApi, Badge +from rebrickable_api.rest import ApiException +from rebrickable_cli.cli.common import pass_global, pass_usersapi, object_print, add_typed_subcommands, \ + get_or_push_context_obj +from rebrickable_cli.utils import get_data, write_data, DATA_PATH + + +@click.group(help='login a certain user or get global badges information') +@pass_global +@click.pass_context +def users(ctx, global_context): + ctx.obj = UsersApi(global_context.client) + + +@users.command(name='badges') +@pass_usersapi +@object_print +def users_badges_list(api): + return api.users_badges_list() + + +@add_typed_subcommands(Badge) +@users.group('badge') +@pass_usersapi +@click.argument('id', type=int) +@get_or_push_context_obj +def users_badge(api, id): + return api.users_badges_read(id=id) + + +def create_auth(users_api, username=None): + if username is None: + username = input('Username: ') + password = getpass() + return users_api.users_token_create(username, password) + + +@users.command(name='login', help='login a certain user (store its user token)') +@pass_usersapi +@click.option('--other', + help='login another user and not the default (which will be used by default in "rebrickable user [...]")', + is_flag=True, + default=False) +@click.argument('username', required=False) +def users_login(users_api, other, username=None): + try: + users_token = create_auth(users_api, username) + data = get_data() + if not other: + data.setdefault('users', {}).setdefault('%%default%%', {})['token'] = users_token + data.setdefault('users', {}).setdefault(username, {})['token'] = users_token + write_data(data) + + print('OK, saved users token into %s' % DATA_PATH) + except ApiException as e: + print('Login failed, response was %s' % e.body) + raise click.Abort() \ No newline at end of file diff --git a/cli/rebrickable_cli/utils.py b/cli/rebrickable_cli/utils.py index caeeb63..0810093 100644 --- a/cli/rebrickable_cli/utils.py +++ b/cli/rebrickable_cli/utils.py @@ -1,6 +1,9 @@ import json import os +import re +from enum import EnumMeta +import click from appdirs import AppDirs config_dir = AppDirs('pyrebrickable').user_config_dir @@ -13,12 +16,6 @@ DATA_PATH = os.path.join(config_dir, 'config.json') -def update_data(key, value, data_path=DATA_PATH): - data = get_data(data_path) - data[key] = value - write_data(data, data_path) - - def write_data(data, data_path=DATA_PATH): with open(data_path, 'w+') as data_file: json.dump(data, data_file) @@ -33,3 +30,44 @@ def get_data(data_path=DATA_PATH): except ValueError: return {} + +class EnumType(click.Choice): + def __init__(self, enum, casesensitive=True): + if isinstance(enum, EnumMeta): + choices = enum.__members__ + else: + raise TypeError("`enum` must be `Enum`") + + if not casesensitive: + choices = (_.lower() for _ in choices) + + self.__enum = enum + self.__casesensitive = casesensitive + + # TODO choices do not have the save order as enum + super(EnumType, self).__init__(list(sorted(set(choices)))) + + def convert(self, value, param, ctx): + if not self.__casesensitive: + value = value.lower() + + value = super(EnumType, self).convert(value, param, ctx) + + if not self.__casesensitive: + return next(_ for _ in self._EnumType__enum if _.name.lower() == + value.lower()) + else: + return next(_ for _ in self._EnumType__enum if _.name == value) + + def get_metavar(self, param): + word = self.__enum.__name__ + + # Stolen from jpvanhal/inflection + word = re.sub(r"([A-Z]+)([A-Z][a-z])", r'\1_\2', word) + word = re.sub(r"([a-z\d])([A-Z])", r'\1_\2', word) + word = word.replace("-", "_").lower().split("_") + + if word[-1] == "enum": + word.pop() + + return ("_".join(word)).upper() \ No newline at end of file diff --git a/cli/setup.py b/cli/setup.py index 49c1ecc..9243dcf 100644 --- a/cli/setup.py +++ b/cli/setup.py @@ -10,6 +10,7 @@ Generated by: https://github.com/swagger-api/swagger-codegen.git """ import os +import sys from setuptools import setup, find_packages # noqa: H301 @@ -23,9 +24,14 @@ # http://pypi.python.org/pypi/setuptools REQUIRES = ["pyrebrickable_api", - 'appdirs', + 'appdirs', 'enum34', 'PyYaml', "click >=6"] + +if sys.version_info[:2] < (3, 4): + REQUIRES.append(['enum34']) + + setup( name=NAME, version=VERSION, @@ -45,7 +51,7 @@ keywords=["LEGO", "Rebrickable", "CLI"], entry_points={ 'console_scripts': [ - 'rebrickable=rebrickable_cli.cli:main' + 'rebrickable=rebrickable_cli.cli.main:main' ] }, install_requires=REQUIRES, diff --git a/dev-requirements.txt b/dev-requirements.txt index 199bad0..e32ee8e 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -7,6 +7,7 @@ mock -e api -e cli -e data +-e . pytest-cov coveralls tox @@ -14,3 +15,4 @@ tox-travis setuptools>=38.6.0 twine>=1.11.0 prance +jsondiff diff --git a/patch_swagger.py b/patch_swagger.py index 63c17ef..55f6930 100755 --- a/patch_swagger.py +++ b/patch_swagger.py @@ -83,6 +83,8 @@ def ref(cls): String = {'type': 'string'} Boolean = {'type': 'boolean'} Url = {'type': 'string', 'format': 'uri'} + ArrayOfInteger = {'type': 'array', 'items': Integer} + ArrayOfString = {'type': 'array', 'items': String} classes = { 'Color': { @@ -90,6 +92,7 @@ def ref(cls): "name": String, "rgb": String, "is_trans": Boolean, + 'external_ids': ref('ExternalColorIds') }, 'Theme': { "id": Integer, @@ -110,8 +113,14 @@ def ref(cls): "part_num": String, "name": String, "part_cat_id": Integer, + "year_from": Integer, + "year_to": Integer, "part_url": Url, - "part_img_url": Url + "part_img_url": Url, + "prints": ArrayOfString, + "molds": ArrayOfString, + "alternates": ArrayOfString, + "external_ids": ref('ExternalIds'), }, 'InventoryPart': { "id": Integer, @@ -187,7 +196,7 @@ def ref(cls): }, 'PartColorsList': { "num_sets": Integer, - "elements": {'type': 'array', 'items': Integer}, + "elements": ArrayOfInteger, "num_set_parts": Integer, "color_id": Integer, "part_img_url": Url, @@ -195,7 +204,7 @@ def ref(cls): }, "PartColorsElement": { 'num_sets': Integer, - 'elements': {'type': 'array', 'items': Integer}, + 'elements': ArrayOfString, 'num_set_parts': Integer, 'year_from': Integer, 'part_img_url': Url, @@ -203,6 +212,23 @@ def ref(cls): } } non_array_classes = { + 'ExternalColorId': { + 'ext_ids': ArrayOfInteger, + 'ext_descrs': {'type': 'array', 'items': ArrayOfString} + }, + 'ExternalColorIds': { + 'BrickLink': ref('ExternalColorId'), + 'LEGO': ref('ExternalColorId'), + 'BrickOwl': ref('ExternalColorId'), + 'Peeron': ref('ExternalColorId'), + 'LDraw': ref('ExternalColorId') + }, + 'ExternalIds': { + "BrickLink": ArrayOfString, + "BrickOwl": ArrayOfString, + "LDraw": ArrayOfString, + "LEGO": ArrayOfString + }, 'BuildOptions': { "ignore_minifigs": Boolean, "sort_by": Integer, @@ -220,6 +246,7 @@ def ref(cls): "inc_owned": Boolean, "ignore_print": Boolean, "inc_premium": Boolean, + "theme": Integer, "ignore_mold": Boolean }, 'Build': { @@ -232,7 +259,7 @@ def ref(cls): "num_missing": Integer }, 'Rewards': { - "badges": {"type": "array", "items": Integer}, + "badges": ArrayOfInteger, "points": Integer, "level": Integer }, @@ -270,6 +297,26 @@ def ref(cls): } }) + api['paths']['/api/v3/users/{user_token}/sets/sync/']['post']['parameters'] = [ + { + "description": "user_token", + "in": "path", + "name": "user_token", + "required": True, + "type": "string" + }, + { + "description": "json_set_list", + "in": "body", + "schema": ref('ArrayOfSetListSets'), + "name": "json_set_list", + "required": True + }, + ] + api['paths']['/api/v3/users/{user_token}/sets/sync/']['post']['consumes'] = [ + 'application/json' + ] + for cls in classes: api['definitions'].update(get_typedef_array(cls)) api['definitions'].update(get_typedef(cls, classes[cls])) @@ -327,6 +374,7 @@ def set_schema(url, schema, code='200', method='get'): set_schema('/api/v3/users/{user_token}/lost_parts/', ref('ArrayOfLostParts')) set_schema('/api/v3/users/{user_token}/parts/', ref('ArrayOfPartListParts')) set_schema('/api/v3/users/{user_token}/sets/', ref('SetListSet'), '201', 'post') + set_schema('/api/v3/users/{user_token}/setlists/', ref('SetList'), '201', 'post') # TODO # '/api/v3/users/{user_token}/lost_parts/', 'POST', @@ -338,7 +386,6 @@ def set_schema(url, schema, code='200', method='get'): # '/api/v3/users/{user_token}/partlists/{list_id}/parts/{part_num}/{color_id}/', 'DELETE', # '/api/v3/users/{user_token}/partlists/{list_id}/parts/{part_num}/{color_id}/', 'PUT', # '/api/v3/users/{user_token}/partlists/{list_id}/', 'PUT', - # '/api/v3/users/{user_token}/setlists/', 'POST', # '/api/v3/users/{user_token}/setlists/{list_id}/', 'DELETE', # '/api/v3/users/{user_token}/setlists/{list_id}/', 'PATCH', # '/api/v3/users/{user_token}/setlists/{list_id}/sets/{set_num}/', 'DELETE', diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..a951302 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,43 @@ +import pytest +from click.testing import CliRunner +from mock import mock, patch + +from rebrickable_api import * + + +@pytest.fixture(scope='session') +def runner(): + return CliRunner() + + +def _read_echo(type_): + def fun(*args, **kwargs): + return type_(*args, **kwargs) + + return fun + + +@pytest.fixture +def mocked_lego_api(): + with mock.patch('rebrickable_api.LegoApi', spec=LegoApi) as ctx_mock, \ + patch.object(LegoApi, 'lego_colors_read', side_effect=_read_echo(Color)), \ + patch.object(LegoApi, 'lego_elements_read', side_effect=_read_echo(Element)), \ + patch.object(LegoApi, 'lego_mocs_read', side_effect=_read_echo(Moc)), \ + patch.object(LegoApi, 'lego_part_categories_read', side_effect=_read_echo(PartCategory)), \ + patch.object(LegoApi, 'lego_parts_colors_read', side_effect=lambda *args, **kwargs: PartColorsElement()), \ + patch.object(LegoApi, 'lego_parts_read', side_effect=_read_echo(Part)), \ + patch.object(LegoApi, 'lego_sets_read', side_effect=_read_echo(Set)), \ + patch.object(LegoApi, 'lego_themes_read', side_effect=_read_echo(Theme)): + yield ctx_mock + + +@pytest.fixture +def mocked_users_api(): + with mock.patch('rebrickable_api.UsersApi', spec=UsersApi) as ctx_mock, \ + patch.object(UsersApi, 'users_badges_read', side_effect=_read_echo(Badge)), \ + patch.object(UsersApi, 'users_build_read', side_effect=lambda *args, **kwargs: Build()), \ + patch.object(UsersApi, 'users_partlists_parts_read', side_effect=_read_echo(PartListPart)), \ + patch.object(UsersApi, 'users_partlists_read', side_effect=_read_echo(PartList)), \ + patch.object(UsersApi, 'users_setlists_read', side_effect=_read_echo(SetList)), \ + patch.object(UsersApi, 'users_sets_read', side_effect=_read_echo(Set)): + yield ctx_mock diff --git a/tests/test_cli.py b/tests/test_cli.py index 425c168..7ee18fe 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -4,303 +4,245 @@ """Tests for `pyrebrickable` package.""" import click -import mock -import pytest -from click.testing import CliRunner -from mock import MagicMock +from mock import patch, Mock +from functools import wraps -from rebrickable_api import LegoApi, UsersApi, UsersTokenResponse +from rebrickable_api import Part, Color, Element, Moc, LegoApi, PartColorsElement from rebrickable_api.rest import ApiException -from rebrickable_cli import cli -from rebrickable_cli.cli import (lego_colors_list, - lego_colors_read, - lego_elements_read, - lego_mocs_parts_list, - lego_mocs_read, - lego_part_categories_list, - lego_part_categories_read, - lego_parts_colors_list, - lego_parts_colors_read, - lego_parts_colors_sets_list, - lego_parts_list, - lego_parts_read, - lego_sets_alternates_list, - lego_sets_list, - lego_sets_parts_list, - lego_sets_read, - lego_sets_sets_list, - lego_themes_list, - users_allparts_list, - users_badges_list, - users_badges_read, - users_build_read, - users_lost_parts_create, - users_lost_parts_delete, - users_lost_parts_list, - users_partlists_create, - users_partlists_delete, - users_partlists_list, - users_partlists_partial_update, - users_partlists_parts_create, - users_partlists_parts_delete, - users_partlists_parts_list, - users_partlists_parts_read, - users_partlists_parts_update, - users_partlists_read, - users_partlists_update, - users_parts_list, - users_profile_list, - users_setlists_create, - users_setlists_delete, - users_setlists_list, - users_setlists_partial_update, - users_setlists_read, - users_setlists_sets_create, - users_setlists_sets_delete, - users_setlists_sets_list, - users_setlists_sets_partial_update, - users_setlists_sets_read, - users_setlists_sets_update, - users_setlists_update, - users_sets_create, - users_sets_delete, - users_sets_list, - users_sets_read, - users_sets_sync_create, - users_sets_update, - users_token_create, lego_themes_read, - - UsersContext, - users, - main, - lego) - - -@pytest.fixture(scope='function') -def runner(request): - return CliRunner() +from rebrickable_cli.cli.common import pass_usercontext, pass_global, GlobalContext +from rebrickable_cli.cli.lego import lego, lego_part, lego_part_color, lego_color, lego_element, lego_moc +from rebrickable_cli.cli.main import main +from rebrickable_cli.cli.user import user def test_command_line_interface(runner): """Test the CLI.""" - result = runner.invoke(cli.main) + result = runner.invoke(main) assert result.exit_code == 0 assert 'main' in result.output - help_result = runner.invoke(cli.main, ['--help']) + help_result = runner.invoke(main, ['--help']) assert help_result.exit_code == 0 - assert '--help Show this message and exit.' in help_result.output - - -def test_command_line_interface_api_calls(runner): - lego_entrypoints = [ - lego_colors_list, - lego_colors_read, - lego_elements_read, - lego_mocs_parts_list, - lego_mocs_read, - lego_part_categories_list, - lego_part_categories_read, - lego_parts_colors_list, - lego_parts_colors_read, - lego_parts_colors_sets_list, - lego_parts_list, - lego_parts_read, - lego_sets_alternates_list, - lego_sets_list, - lego_sets_parts_list, - lego_sets_read, - lego_sets_sets_list, - lego_themes_list, - lego_themes_read] - users_entrypoints = [ - users_allparts_list, - users_badges_list, - users_badges_read, - users_build_read, - users_lost_parts_create, - users_lost_parts_delete, - users_lost_parts_list, - users_partlists_create, - users_partlists_delete, - users_partlists_list, - users_partlists_partial_update, - users_partlists_parts_create, - users_partlists_parts_delete, - users_partlists_parts_list, - users_partlists_parts_read, - users_partlists_parts_update, - users_partlists_read, - users_partlists_update, - users_parts_list, - users_profile_list, - users_setlists_create, - users_setlists_delete, - users_setlists_list, - users_setlists_partial_update, - users_setlists_read, - users_setlists_sets_create, - users_setlists_sets_delete, - users_setlists_sets_list, - users_setlists_sets_partial_update, - users_setlists_sets_read, - users_setlists_sets_update, - users_setlists_update, - users_sets_create, - users_sets_delete, - users_sets_list, - users_sets_read, - users_sets_sync_create, - users_sets_update, - users_token_create - ] - - def treat_(fun, obj, mocked_call): - args = ['0' for param in fun.params] - result = runner.invoke(fun, obj=obj, args=args) - assert mocked_call.called - print(fun.callback.__name__) - assert result.exception is None - - for func in lego_entrypoints: - name = func.callback.__name__ - with mock.patch('rebrickable_api.LegoApi', spec=LegoApi) as ctx_mock: - mocked_call = MagicMock() - setattr(ctx_mock, name, mocked_call) - treat_(func, ctx_mock, mocked_call) - - for func in users_entrypoints: - name = func.callback.__name__ - with mock.patch('rebrickable_cli.cli.UsersContext', spec=UsersContext) as ctx_mock: - mocked_call = MagicMock() - ctx_mock.api = MagicMock(spec=UsersApi) - ctx_mock.token = 'ttt' - setattr(ctx_mock.api, name, mocked_call) - treat_(func, ctx_mock, mocked_call) + assert 'Show this message and exit.' in help_result.output @main.command(name='test') -@click.pass_obj +@pass_global def command_dummy(obj): pass -def data_context(value={}): - def get_data(): +def mocked_data(value=None): + def get_(): return value - return mock.patch('rebrickable_cli.cli.get_data', side_effect=get_data) + def decorator(fun): + @patch('rebrickable_cli.cli.common.get_data', new=Mock(side_effect=get_)) + @patch('rebrickable_cli.cli.main.get_data', new=Mock(side_effect=get_)) + @patch('rebrickable_cli.cli.users.get_data', new=Mock(side_effect=get_)) + @wraps(fun) + def wrapper(*args, **kwargs): + return fun(*args, **kwargs) + return wrapper + return decorator + +def with_mocked_api(): + def decorator(fun): + def get_part(part_num, *args, **kwargs): + return Part(part_num=part_num) + @wraps(fun) + @patch.object(LegoApi, 'lego_parts_read', Mock(side_effect=get_part)) + def wrapper(*args, **kwargs): + return fun(*args, **kwargs) + + return wrapper + return decorator + +@mocked_data({'api_key': 'api_key_value'}) def test_main_command_pass_obj_valid(runner): - with data_context({'api_key':'api_key_value'}): - result = runner.invoke(main, ['test']) - assert result.exception is None + result = runner.invoke(main, ['test']) + assert result.exception is None +@mocked_data({}) def test_main_command_pass_obj_invalid(runner): - with data_context(): - result = runner.invoke(main, ['test']) - assert result.exception is not None + result = runner.invoke(main, ['test']) + assert result.exception is not None -@users.command(name='test') -@click.pass_obj -def users_test(obj): - pass +@user.command(name='test') +@pass_usercontext +def user_test(users_context): + assert users_context.token == 'user_token_value' +@mocked_data({'api_key': 'api_key_value', 'users': {'%%default%%': {'token': 'user_token_value'}}}) def test_users_command_pass_obj_valid(runner): - with data_context({'api_key':'api_key_value', 'users_token': 'users_token_value'}): - result = runner.invoke(main, ['users', 'test']) - assert result.exception is None + result = runner.invoke(main, ['user', 'test']) + assert result.exception is None +@mocked_data(None) def test_users_command_pass_obj_invalid(runner): - with data_context(): - result = runner.invoke(main, ['users', 'test']) - assert result.exception is not None + result = runner.invoke(main, ['user', 'test']) + assert result.exception is not None + + +@patch('rebrickable_cli.cli.main.get_api_client', new=Mock()) +@patch.object(LegoApi, 'lego_parts_read', Mock(return_value=Part(part_num='3002'))) +def test_lego_part_command_pass_obj(runner): + @lego_part.command(name='test') + @click.pass_context + def lego_part_test(ctx): + part = ctx.find_object(Part) + assert part.part_num == "3002" + + result = runner.invoke(main, ['lego', 'part', '3002', 'test']) + assert result.exception is None + + +@patch('rebrickable_cli.cli.main.get_api_client', new=Mock()) +@patch.object(LegoApi, 'lego_parts_read', Mock(return_value=Part(part_num='3002'))) +@patch.object(LegoApi, 'lego_parts_colors_read', Mock(return_value=PartColorsElement(elements=[Element(color=Color(id=5), part=Part(part_num="3002"))]))) +def test_lego_part_color_command_pass_obj(runner): + @lego_part_color.command(name='test') + @click.pass_context + def lego_part_color_test(ctx): + part_colors_element = ctx.find_object(PartColorsElement).elements[0] + assert part_colors_element.color.id == 5 + assert part_colors_element.part.part_num == "3002" + + result = runner.invoke(main, ['lego', 'part', '3002', 'color', '5', 'test']) + assert result.exception is None + + +@patch('rebrickable_cli.cli.main.get_api_client', new=Mock()) +@patch.object(LegoApi, 'lego_colors_read', Mock(return_value=Color(id=1234))) +def test_lego_color_command_pass_obj(runner): + @lego_color.command(name='test') + @click.pass_context + def lego_color_test(ctx): + color = ctx.find_object(Color) + assert color.id == 1234 + + result = runner.invoke(main, ['lego', 'color', '1234', 'test']) + assert result.exception is None + + +@patch('rebrickable_cli.cli.main.get_api_client', new=Mock()) +@patch.object(LegoApi, 'lego_elements_read', Mock(return_value=Element(element_id=1234))) +def test_lego_element_command_pass_obj(runner): + @lego_element.command(name='test') + @click.pass_context + def lego_element_test(ctx): + element = ctx.find_object(Element) + assert element.element_id == 1234 + + result = runner.invoke(main, ['lego', 'element', '1234', 'test']) + assert result.exception is None + + +@patch('rebrickable_cli.cli.main.get_api_client', new=Mock()) +@patch.object(LegoApi, 'lego_mocs_read', Mock(return_value = Moc(set_num='MOC-1234'))) +def test_lego_moc_command_pass_obj(runner): + @lego_moc.command(name='test') + @click.pass_context + def lego_moc_test(ctx): + moc = ctx.find_object(Moc) + assert moc.set_num == "MOC-1234" + + result = runner.invoke(main, ['lego', 'moc', 'MOC-1234', 'test']) + assert result.exception is None @lego.command(name='test') -@click.pass_obj -def lego_test(obj): +def lego_test(): pass +@patch('rebrickable_cli.cli.main.get_api_client', new=Mock()) +@mocked_data({'api_key': 'api_key_value'}) def test_lego_command_pass_obj_valid(runner): - with data_context({'api_key':'api_key_value'}): - result = runner.invoke(main, ['lego', 'test']) - assert result.exception is None + result = runner.invoke(main, ['lego', 'test']) + assert result.exception is None +@mocked_data({}) def test_lego_command_pass_invalid(runner): - with data_context(): - result = runner.invoke(main, ['lego', 'test']) - assert result.exception is not None + result = runner.invoke(main, ['lego', 'test']) + assert result.exception is not None +@patch('rebrickable_cli.cli.main.get_api_client', new=Mock()) +@mocked_data({'api_key': 'api_key_value'}) def test_users_login_no_username(runner): - with data_context({'api_key':'api_key_value'}): - result = runner.invoke(main, ['users', 'login']) - # no username - assert result.exception is not None + result = runner.invoke(main, ['users', 'login']) + # no username + assert result.exception is not None +@mocked_data({'api_key': 'api_key_value'}) def test_users_login(runner): - def users_token_create(s, user, password): - assert user == 'username' - assert password == 'password' - return UsersTokenResponse(user_token='user_token') + def write_data(data): + assert data == {'api_key': 'api_key_value', + 'users': { + '%%default%%': { + 'token': 'user_token' + }, + 'username': { + 'token': 'user_token' + } + }} + + with patch('rebrickable_cli.cli.users.create_auth', return_value='user_token'), \ + patch('rebrickable_cli.cli.users.write_data', side_effect=write_data): + result = runner.invoke(main, ['users', 'login', 'username']) - def update_data(key, value): - assert key == 'users_token' - assert value == 'user_token' + assert result.exception is None - def getpass(): - return 'password' - with data_context({'api_key':'api_key_value'}), \ - mock.patch('rebrickable_cli.cli.getpass', new=getpass), \ - mock.patch.object(UsersApi,'users_token_create', new=users_token_create),\ - mock.patch('rebrickable_cli.cli.update_data', side_effect=update_data): +@mocked_data({'api_key': 'api_key_value'}) +def test_users_login_other(runner): + def write_data(data): + assert data == {'api_key': 'api_key_value', + 'users': { + 'username': { + 'token': 'user_token' + } + }} - result = runner.invoke(main, ['users', 'login', 'username']) + with patch('rebrickable_cli.cli.users.create_auth', return_value='user_token'), \ + patch('rebrickable_cli.cli.users.write_data', side_effect=write_data): + result = runner.invoke(main, ['users', 'login', '--other', 'username']) assert result.exception is None +@mocked_data({'api_key': 'api_key_value'}) def test_users_login_invalid_login(runner): - def users_token_create(s, user, password): + def create_auth(users_api, username): raise ApiException() - def getpass(): - return 'password' - - with data_context({'api_key': 'api_key_value'}), \ - mock.patch('rebrickable_cli.cli.getpass', new=getpass), \ - mock.patch.object(UsersApi, 'users_token_create', new=users_token_create): + with patch('rebrickable_cli.cli.users.create_auth', side_effect=create_auth): result = runner.invoke(main, ['users', 'login', 'username']) - assert result.exception is not None + assert result.exception is not None +@mocked_data({'api_key': 'api_key_value'}) def test_users_profile_invalid_login(runner): - with data_context({'api_key': 'api_key_value'}): - result = runner.invoke(main, ['users', 'profile']) + result = runner.invoke(main, ['users', 'profile']) - assert result.exception is not None + assert result.exception is not None def test_register_valid(runner): - def getpass(prompt): - return 'api_key_value' - - def update_data(key, value): - assert key == 'api_key' - assert value == 'api_key_value' + def write_data(data): + assert data['api_key'] == 'api_key_value' - with mock.patch('rebrickable_cli.cli.getpass', new=getpass), \ - mock.patch('rebrickable_cli.cli.update_data', side_effect=update_data): + with patch('rebrickable_cli.cli.main.get_api_key', return_value='api_key_value'), \ + patch('rebrickable_cli.cli.main.write_data', side_effect=write_data): result = runner.invoke(main, ['register']) assert result.exception is None diff --git a/tests/test_cli_integration.py b/tests/test_cli_integration.py new file mode 100644 index 0000000..cab18cb --- /dev/null +++ b/tests/test_cli_integration.py @@ -0,0 +1,387 @@ +from __future__ import print_function + +from rebrickable_api import Set, Part, Color, Moc, PartList, PartListPart, SetList, SetListSet +from six import StringIO + +import pytest +from click import Context, Command + +from rebrickable_cli.cli.common import UserContext +from rebrickable_cli.cli.lego import * +from rebrickable_cli.cli.main import * +from rebrickable_cli.cli.user import * +from rebrickable_cli.cli.users import * + + +def parametrized(*args, **kwargs): + def decorator(fun): + if 'ids' not in kwargs: + def get_id(param): + if isinstance(param, Command): + return param.callback.__name__ + return str(param) + + kwargs['ids'] = get_id + return pytest.mark.parametrize(*args, **kwargs)(fun) + + return decorator + + +def context_stack(*objs): + ctx = None + for obj in objs: + if ctx is None: + ctx = Context(main, obj=obj) + else: + ctx = Context(main, obj=obj, parent=ctx) + return ctx + + +def do_test(cli_func, method, cli_args, call_kwargs, runner, api, context): + mocked_method = getattr(api, method) + mocked_method.return_value = 'stuff' + result = runner.invoke(cli_func, cli_args, obj=api, parent=context) + if result.exit_code != 0: + print(result.output) + pass + mocked_method.assert_called_with(**call_kwargs) + assert 'stuff\n' == result.output + + +# legoapi +lego_operations = [ + (lego_colors, 'lego_colors_list', [], {}), + (lego_color, 'lego_colors_read', ['6'], {'id': 6}), + (lego_element, 'lego_elements_read', ['1234'], {'element_id': '1234'}), + (lego_part_categories, 'lego_part_categories_list', [], {}), + (lego_part_category, 'lego_part_categories_read', ['17859'], {'id': 17859}), + (lego_parts, 'lego_parts_list', [], {}), + (lego_sets, 'lego_sets_list', [], {}), + (lego_themes, 'lego_themes_list', [], {}), + (lego_theme, 'lego_themes_read', ['1485'], {'id': '1485'}), +] + + +@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], lego_operations) +def test_lego_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api): + context = context_stack( + GlobalContext(OutputFormatter(output=print), None), + ) + + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api, context) + + +lego_set_operations = [ + (lego_set, 'lego_sets_read', ['75192-1'], {}), + (lego_set_alternates, 'lego_sets_alternates_list', [], {}), + (lego_set_parts, 'lego_sets_parts_list', [], {}), + (lego_set_sets, 'lego_sets_sets_list', [], {}), +] + +@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], lego_set_operations) +def test_lego_set_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api): + context = context_stack( + GlobalContext(OutputFormatter(output=print), None), + Set(set_num='75192-1') + ) + + call_kwargs['set_num'] = '75192-1' + + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api, context) + + +lego_part_operations = [ + (lego_part_colors, 'lego_parts_colors_list', [], {}), + (lego_part, 'lego_parts_read', ['3004'], {}), +] + + +@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], lego_part_operations) +def test_lego_part_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api): + context = context_stack( + GlobalContext(OutputFormatter(output=print), None), + Part(part_num='3004') + ) + + call_kwargs['part_num'] = '3004' + + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api, context) + + +lego_part_color_operations = [ + (lego_part_color, 'lego_parts_colors_read', ['45'], {}), + (lego_part_color_sets, 'lego_parts_colors_sets_list', [], {}), +] + + +@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], lego_part_color_operations) +def test_lego_part_color_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api): + context = context_stack( + GlobalContext(OutputFormatter(output=print), None), + Part(part_num='3020'), + Color(id=45), + ) + + call_kwargs['part_num'] = '3020' + call_kwargs['color_id'] = 45 + + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api, context) + + +lego_moc_operations = [ + (lego_moc_parts, 'lego_mocs_parts_list', [], {}), + (lego_moc, 'lego_mocs_read', ['MOC-5634'], {}), +] + + +@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], lego_moc_operations) +def test_lego_moc_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api): + context = context_stack( + GlobalContext(OutputFormatter(output=print), None), + Moc(set_num='MOC-5634') + ) + call_kwargs['set_num'] = 'MOC-5634' + + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api, context) + + +users_operations = [ + (user_partlists_create, 'users_partlists_create', ['test'], {'name': 'test'}), + (user_partlists_list, 'users_partlists_list', [], {}), + (user_allparts, 'users_allparts_list', [], {}), + + (user_build, 'users_build_read', ['75192-1'], {'set_num': '75192-1'}), + (user_lost_parts_create, 'users_lost_parts_create', ['14523'], {'inv_part_id': 14523}), + (user_lost_parts_delete, 'users_lost_parts_delete', ['47859'], {'id': 47859}), + (user_lost_parts_list, 'users_lost_parts_list', [], {}), + (user_parts, 'users_parts_list', [], {}), + + (user_setlists_create, 'users_setlists_create', ['test'], {'name': 'test'}), + (user_setlists_list, 'users_setlists_list', [], {}), + + (user_sets_create, 'users_sets_create', ['1234-4'], {'set_num': '1234-4'}), + (user_sets_list, 'users_sets_list', [], {}), + (user_sets_sync, 'users_sets_sync_create', ["-f", StringIO("{\"test\": \"foo\"}")], + {'array_of_set_list_sets': {'test': 'foo'}}), + (user_profile, 'users_profile_list', [], {}), +] + + +@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], users_operations) +def test_users_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): + context = context_stack( + GlobalContext(OutputFormatter(output=print), None), + UserContext(api=mocked_users_api, token='abcdef') + ) + call_kwargs['user_token'] = 'abcdef' + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api, context) + + +users_no_token_operations = [ + (users_badges_list, 'users_badges_list', [], {}), + (users_badge, 'users_badges_read', ['12345'], {'id': 12345}), +] + + +@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], users_no_token_operations) +def test_users_no_token_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): + context = context_stack( + GlobalContext(OutputFormatter(output=print), None), + UserContext(api=mocked_users_api, token='abcdef') + ) + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api, context) + + +users_partlist_operations = [ + (user_partlist_partial_update, 'users_partlists_partial_update', [], {}), + (user_partlist_delete, 'users_partlists_delete', [], {}), + (user_partlist_parts_create, 'users_partlists_parts_create', ['3004', '4', '45'], + {'part_num': '3004', 'color_id': 45, 'quantity': 4}), + (user_partlist_parts_delete, 'users_partlists_parts_delete', ['35', '3002'], {'part_num': '3002', 'color_id': 35}), + (user_partlist_parts_list, 'users_partlists_parts_list', [], {}), + (user_partlist, 'users_partlists_read', ['987654321'], {}), + (user_partlist_update, 'users_partlists_update', ['test'], {'name': 'test'}), +] + + +@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], users_partlist_operations) +def test_users_partlist_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): + context = context_stack( + GlobalContext(OutputFormatter(output=print), None), + UserContext(api=mocked_users_api, token='abcdef'), + PartList(id=987654321) + ) + + call_kwargs['list_id'] = 987654321 + call_kwargs['user_token'] = 'abcdef' + + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api, context) + + +users_partlist_part_operations = [ + (user_partlist_part, 'users_partlists_parts_read', ['45', '3004'], + {'color_id': 45}), + (user_partlist_part_update, 'users_partlists_parts_update', ['475'], + {'quantity': 475}), +] + + +@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], users_partlist_part_operations) +def test_users_partlist_part_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): + context = context_stack( + GlobalContext(OutputFormatter(output=print), None), + UserContext(api=mocked_users_api, token='abcdef'), + PartList(id=987654321), + PartListPart(color=Color(id=45), part=Part(part_num='3004')) + ) + call_kwargs['color_id'] = 45 + call_kwargs['part_num'] = '3004' + call_kwargs['list_id'] = 987654321 + call_kwargs['user_token'] = 'abcdef' + + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api, context) + + +users_setlist_operations = [ + (user_setlist, 'users_setlists_read', ['987654321'], {}), + (user_setlist_delete, 'users_setlists_delete', [], {}), + (user_setlist_sets_create, 'users_setlists_sets_create', ['1234-1'], {'set_num': '1234-1'}), + (user_setlist_sets_list, 'users_setlists_sets_list', [], {}), + (user_setlist_update, 'users_setlists_update', ['test'], {'name': 'test'}), + (user_setlist_partial_update, 'users_setlists_partial_update', [], {}), +] + + +@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], users_setlist_operations) +def test_users_setlist_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): + context = context_stack( + GlobalContext(OutputFormatter(output=print), None), + UserContext(api=mocked_users_api, token='abcdef'), + SetList(id=987654321) + ) + + call_kwargs['list_id'] = 987654321 + call_kwargs['user_token'] = 'abcdef' + + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api, context) + + +users_setlist_set_operations = [ + (user_setlist_set_delete, 'users_setlists_sets_delete', [], {}), + (user_setlist_set_partial_update, 'users_setlists_sets_partial_update', ['1357-1'], {}), + (user_setlist_set, 'users_setlists_sets_read', ['1357-1'], {}), + (user_setlist_set_update, 'users_setlists_sets_update', [], {}), +] + + +@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], users_setlist_set_operations) +def test_users_setlist_set_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): + context = context_stack( + GlobalContext(OutputFormatter(output=print), None), + UserContext(api=mocked_users_api, token='abcdef'), + SetList(id=987654321), + SetListSet(set_num='1357-1') + ) + + call_kwargs['list_id'] = 987654321 + call_kwargs['user_token'] = 'abcdef' + call_kwargs['set_num'] = '1357-1' + + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api, context) + + +users_set_operations = [ + (user_set_delete, 'users_sets_delete', [], {}), + (user_set, 'users_sets_read', ['75192-1'], {}), + (user_set_update, 'users_sets_update', [], {}), +] + + +@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], users_set_operations) +def test_users_set_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): + context = context_stack( + GlobalContext(OutputFormatter(output=print), None), + UserContext(api=mocked_users_api, token='abcdef'), + Set(set_num='75192-1') + ) + + call_kwargs['set_num'] = '75192-1' + call_kwargs['user_token'] = 'abcdef' + + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api, context) + +""" + +lego + - colors: + - list + - color: + - read + - element: + - read + - moc: + - read + - parts + - part_categories: + - list + - part_category: + - read + - parts: + - list + - part: + - read + - colors + - color : + - sets + - sets: + - list + - set: + - read + - alternates + - parts + - sets + - themes: + - list + - theme: + - read + +users: + - _token + - badges + - badge + +user + - allparts + - build + - lost_parts: + - list + - lost_part: + - read + - partlists: + - list + - partlist: + - read + - parts: + - list + - part: + - read + + - parts: + - list + - profile: + - read + - setlists: + - list + - setlist: + - read + - sets: + - list + - set: + - read + - sets: + - list + - sync + - set: + - read + +""" \ No newline at end of file diff --git a/tests/test_cli_utils.py b/tests/test_cli_utils.py index b50b62d..18ecbaa 100644 --- a/tests/test_cli_utils.py +++ b/tests/test_cli_utils.py @@ -1,29 +1,36 @@ import json import mock -import pytest -from rebrickable_cli.cli import get_api_client, get_users_context -from rebrickable_cli.utils import get_data, write_data, update_data +from rebrickable_cli.cli.common import get_user_context +from rebrickable_cli.cli.main import get_api_client +from rebrickable_cli.utils import get_data, write_data def test_data(): api_key = 'nice_api_key' users_token = 'nice_users_token' - read_data_dict = {'api_key': api_key, 'users_token': users_token} + read_data_dict = { + 'api_key': api_key, + 'users': { + '%%default%%': { + 'token': users_token + } + } + } m = mock.mock_open(read_data=json.dumps(read_data_dict)) with mock.patch('{}.open'.format('rebrickable_cli.utils'), m, create=True): data = get_data() - assert data.items() == read_data_dict.items() + assert data == read_data_dict api_client = get_api_client() assert api_client.configuration.api_key['Authorization'] == api_key assert api_client.configuration.api_key_prefix['Authorization'] == 'key' - users_context = get_users_context(api_client) + users_context = get_user_context(api_client) assert users_context.token == users_token assert users_context.api.api_client == api_client @@ -47,18 +54,3 @@ def test_write_data(tmpdir): data2 = get_data(p) assert data2.items() == data.items() - - -def test_update_data(tmpdir): - data = {'api_key': 'old_api_key'} - - p = tmpdir.join('.rebrickable').strpath - - write_data(data, p) - - update_data('api_key', 'new_api_key', p) - - data2 = get_data(p) - - assert data2.keys() == data.keys() - assert data2['api_key'] == 'new_api_key' diff --git a/tests/test_models_integration.py b/tests/test_models_integration.py new file mode 100644 index 0000000..a383535 --- /dev/null +++ b/tests/test_models_integration.py @@ -0,0 +1,93 @@ +import json +from pprint import pprint + +import pytest +import six +from jsondiff import diff + +from rebrickable_api import LegoApi, ApiClient +from rebrickable_cli.cli.common import get_user_context +from rebrickable_cli.cli.main import get_api_client + +""" +assumes a working authentication +and that the data doesn't change much +""" + + +@pytest.fixture(scope='module') +def api_client(): + return get_api_client() + + +@pytest.fixture +def lego_api(api_client): + return LegoApi(api_client) + + +@pytest.fixture +def user_context(api_client): + return get_user_context(api_client) + + +def get_id(element): + if callable(element): + return element.__name__ + return str(element) + + +def remove_nulls(d): + return {k: remove_nulls(v) if isinstance(v, dict) else v for k, v in six.iteritems(d) if v is not None} + + +@pytest.mark.parametrize(['func', 'kwargs'], [ + ('lego_colors_read', dict(id=7)), + ('lego_elements_read', dict(element_id=4245295)), + ('lego_mocs_read', dict(set_num='MOC-5634')), + ('lego_part_categories_read', dict(id=42)), + ('lego_parts_colors_read', dict(color_id=4, part_num='3004')), + ('lego_parts_read', dict(part_num='3004')), + ('lego_parts_read', dict(part_num='4070')), + ('lego_sets_read', dict(set_num='75192-1')), + ('lego_sets_read', dict(set_num='31027-1')), + ('lego_themes_read', dict(id=99)), +], ids=get_id) +@pytest.mark.integration +def test_objects_attributes(func, kwargs, lego_api, api_client): + func = getattr(lego_api, func) + do_test(func, kwargs, api_client) + + +@pytest.mark.parametrize(['func', 'kwargs'], [ + ('users_build_read', dict(set_num='75192-1')), + ('users_partlists_parts_read', dict(list_id=40476, color_id=1, part_num='3298p61')), # user partlist 40476 part 1 3298p61 + ('users_partlists_read', dict(list_id=40476)), + ('users_setlists_read', dict(list_id=221643)), + ('users_sets_read', dict(set_num='8277-1')), +], ids=get_id) +@pytest.mark.integration +def test_objects_attributes(func, kwargs, user_context, api_client): + func = getattr(user_context.api, func) + kwargs['user_token'] = user_context.token + do_test(func, kwargs, api_client) + + +@pytest.mark.integration +def test_users_badges_read_attributes(user_context, api_client): + do_test(user_context.api.users_badges_read, dict(id=63), api_client) + + +def do_test(func, kwargs, api_client): + obj = api_client.sanitize_for_serialization(func(**kwargs)) + obj_no_preload = json.loads(func(_preload_content=False, **kwargs).data) + + # ignore Set last_modified_dt (datetime format) + if 'last_modified_dt' in obj: + obj['last_modified_dt'] = obj_no_preload['last_modified_dt'] + if 'set' in obj: + obj['set']['last_modified_dt'] = obj_no_preload['set']['last_modified_dt'] + + ddiff = diff(obj_no_preload, obj) + + pprint(ddiff) + assert ddiff == {} \ No newline at end of file From 1ea2ff412f7ece783953b2d6cd35b1f016c204b8 Mon Sep 17 00:00:00 2001 From: rienafairefr Date: Fri, 7 Sep 2018 00:17:19 +0200 Subject: [PATCH 07/19] not running integration tests on CI --- cli/rebrickable_cli/utils.py | 5 ++--- tox.ini | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/cli/rebrickable_cli/utils.py b/cli/rebrickable_cli/utils.py index 0810093..56de0e5 100644 --- a/cli/rebrickable_cli/utils.py +++ b/cli/rebrickable_cli/utils.py @@ -25,9 +25,8 @@ def get_data(data_path=DATA_PATH): try: with open(data_path, 'r') as data_file: return json.load(data_file) - except IOError: - return {} - except ValueError: + except (IOError, ValueError): + print('error getting config data from %s' % data_path) return {} diff --git a/tox.ini b/tox.ini index 7f35f56..b78c3ad 100644 --- a/tox.ini +++ b/tox.ini @@ -3,8 +3,8 @@ envlist = py27, py33, py34, py35, py36 skipsdist = true [testenv] -passenv = TRAVIS TRAVIS_JOB_ID TRAVIS_BRANCH YNAB_* NYNAB_* +passenv = TRAVIS TRAVIS_* deps=-r{toxinidir}/dev-requirements.txt commands = - pytest --cov=rebrickable_cli --cov=rebrickable_api + pytest --cov=rebrickable_cli --cov=rebrickable_api -m "not integration" coveralls \ No newline at end of file From 88d36866fa29abc7b41d8b4f5e328c64503999b5 Mon Sep 17 00:00:00 2001 From: rienafairefr Date: Sun, 9 Sep 2018 21:29:40 +0200 Subject: [PATCH 08/19] use decorator to fix pytest introspection --- dev-requirements.txt | 1 + tests/test_cli.py | 15 ++++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/dev-requirements.txt b/dev-requirements.txt index e32ee8e..6a74f81 100644 --- a/dev-requirements.txt +++ b/dev-requirements.txt @@ -16,3 +16,4 @@ setuptools>=38.6.0 twine>=1.11.0 prance jsondiff +decorator diff --git a/tests/test_cli.py b/tests/test_cli.py index 7ee18fe..c019894 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -2,6 +2,7 @@ # -*- coding: utf-8 -*- """Tests for `pyrebrickable` package.""" +import decorator import click from mock import patch, Mock @@ -9,7 +10,7 @@ from rebrickable_api import Part, Color, Element, Moc, LegoApi, PartColorsElement from rebrickable_api.rest import ApiException -from rebrickable_cli.cli.common import pass_usercontext, pass_global, GlobalContext +from rebrickable_cli.cli.common import pass_usercontext, pass_global from rebrickable_cli.cli.lego import lego, lego_part, lego_part_color, lego_color, lego_element, lego_moc from rebrickable_cli.cli.main import main from rebrickable_cli.cli.user import user @@ -35,15 +36,15 @@ def mocked_data(value=None): def get_(): return value - def decorator(fun): + def wrapper(fun, *args, **kwargs): @patch('rebrickable_cli.cli.common.get_data', new=Mock(side_effect=get_)) @patch('rebrickable_cli.cli.main.get_data', new=Mock(side_effect=get_)) @patch('rebrickable_cli.cli.users.get_data', new=Mock(side_effect=get_)) - @wraps(fun) - def wrapper(*args, **kwargs): - return fun(*args, **kwargs) - return wrapper - return decorator + def decorated(*a, **kwa): + return fun(*a, **kwa) + + return decorated + return decorator.decorator(wrapper) def with_mocked_api(): From c5cb43d8cc76481c3a8183236edcfd75c462f710 Mon Sep 17 00:00:00 2001 From: rienafairefr Date: Sun, 9 Sep 2018 22:38:39 +0200 Subject: [PATCH 09/19] only pass the path parameter through, not whole objects --- cli/rebrickable_cli/cli/common.py | 59 ++++--- cli/rebrickable_cli/cli/lego.py | 159 ++++++++---------- cli/rebrickable_cli/cli/user.py | 269 ++++++++++++------------------ cli/rebrickable_cli/cli/users.py | 3 +- tests/lego_cli/__init__.py | 0 tests/lego_cli/test_cli.py | 105 ++++++++++++ tests/test_cli.py | 43 +++-- tests/test_cli_integration.py | 195 +--------------------- tests/test_cli_utils.py | 2 +- tests/test_models_integration.py | 4 +- 10 files changed, 350 insertions(+), 489 deletions(-) create mode 100644 tests/lego_cli/__init__.py create mode 100644 tests/lego_cli/test_cli.py diff --git a/cli/rebrickable_cli/cli/common.py b/cli/rebrickable_cli/cli/common.py index 80aae21..9bd94de 100644 --- a/cli/rebrickable_cli/cli/common.py +++ b/cli/rebrickable_cli/cli/common.py @@ -3,15 +3,26 @@ import click from click import get_current_context -from rebrickable_api import UsersApi, LegoApi +from rebrickable_api import UsersApi from rebrickable_cli.utils import get_data +class LegoContext(object): + def __init__(self, api=None, part_num=None, set_num=None, color_id=None): + self.api = api + self.part_num = part_num + self.set_num = set_num + self.color_id = color_id + + class UserContext(object): - def __init__(self, api, token): + def __init__(self, api=None, user_token=None, list_id=None, part_num=None, color_id=None, set_num=None): self.api = api - self.token = token - self.setlist = None + self.user_token = user_token + self.list_id = list_id + self.part_num = part_num + self.color_id = color_id + self.set_num = set_num def oprint(obj): @@ -25,25 +36,31 @@ def __init__(self, format, client): self.client = client - -def get_or_push_context_obj(fun): - @click.pass_context - @wraps(fun) - def decorated(ctx, *args, **kwargs): - try: - current_obj = fun(ctx, *args, **kwargs) - except: - current_obj = fun(*args, **kwargs) - if ctx.invoked_subcommand is None: - oprint(current_obj) - else: - ctx.obj = current_obj - return current_obj - - return decorated +def get_or_push_context_obj(*decorators): + def decorator(fun): + @click.pass_obj + @click.pass_context + @wraps(fun) + def decorated(ctx, obj, *args, **kwargs): + for attr in kwargs: + setattr(obj, attr, kwargs[attr]) + try: + current_obj = fun(obj, *args, **kwargs) + except: + current_obj = fun(*args, **kwargs) + if ctx.invoked_subcommand is None: + oprint(current_obj) + + current = decorated + for dec in decorators: + current = dec(current) + + return current + return decorator def object_print(fun): + @wraps(fun) def decorated(*args, **kwargs): obj = fun(*args, **kwargs) oprint(obj) @@ -77,6 +94,6 @@ def get_user_context(client, username='%%default%%'): pass_global = click.make_pass_decorator(GlobalContext) -pass_legoapi = click.make_pass_decorator(LegoApi) +pass_lego = click.make_pass_decorator(LegoContext) pass_usercontext = click.make_pass_decorator(UserContext) pass_usersapi = click.make_pass_decorator(UsersApi) \ No newline at end of file diff --git a/cli/rebrickable_cli/cli/lego.py b/cli/rebrickable_cli/cli/lego.py index e321c50..228035c 100644 --- a/cli/rebrickable_cli/cli/lego.py +++ b/cli/rebrickable_cli/cli/lego.py @@ -1,175 +1,152 @@ import click from rebrickable_api import LegoApi, Part, PartColorsElement, Color, Element, Moc, PartCategory, Set, Theme -from rebrickable_cli.cli.common import pass_global, add_typed_subcommands, pass_legoapi, get_or_push_context_obj, \ - object_print, oprint +from rebrickable_cli.cli.common import pass_global, add_typed_subcommands, pass_lego, get_or_push_context_obj, \ + object_print, oprint, LegoContext @click.group(help='LEGO data (parts, sets, themes, etc.)') @pass_global @click.pass_context def lego(ctx, global_context): - ctx.obj = LegoApi(global_context.client) + ctx.obj = LegoContext(api=LegoApi(global_context.client)) @lego.command('parts') -@pass_legoapi +@pass_lego @object_print -def lego_parts(api): - return api.lego_parts_list() +def lego_parts(ctx): + return ctx.api.lego_parts_list() @add_typed_subcommands(Part) @lego.group('part') -@pass_legoapi -@click.argument('part_num') -@get_or_push_context_obj -def lego_part(api, part_num): - return api.lego_parts_read(part_num=part_num) +@pass_lego +@get_or_push_context_obj(click.argument('part_num')) +def lego_part(ctx, part_num): + return ctx.api.lego_parts_read(part_num=ctx.part_num) @lego_part.command('colors') -@pass_legoapi -@click.pass_context +@pass_lego @object_print -def lego_part_colors(ctx, api): - part = ctx.find_object(Part) - return api.lego_parts_colors_list(part_num=part.part_num) +def lego_part_colors(ctx): + return ctx.api.lego_parts_colors_list(part_num=ctx.part_num) @add_typed_subcommands(PartColorsElement) @lego_part.group('color') -@pass_legoapi -@click.pass_context -@click.argument('color_id', type=int) -@get_or_push_context_obj -def lego_part_color(ctx, api, color_id): - part = ctx.find_object(Part) - return api.lego_parts_colors_read(color_id=color_id, part_num=part.part_num) +@pass_lego +@get_or_push_context_obj(click.argument('color_id', type=int)) +def lego_part_color(ctx, color_id): + return ctx.api.lego_parts_colors_read(color_id=color_id, part_num=ctx.part_num) @lego_part_color.command('sets') -@pass_legoapi -@click.pass_context +@pass_lego @object_print -def lego_part_color_sets(ctx, api): - color = ctx.find_object(Color) - part = ctx.find_object(Part) - return api.lego_parts_colors_sets_list(color_id=color.id, part_num=part.part_num) +def lego_part_color_sets(ctx): + return ctx.api.lego_parts_colors_sets_list(color_id=ctx.color_id, part_num=ctx.part_num) @lego.command('colors') -@pass_legoapi +@pass_lego @object_print -def lego_colors(api): - return api.lego_colors_list() +def lego_colors(ctx): + return ctx.api.lego_colors_list() @add_typed_subcommands(Color) @lego.group('color') -@pass_legoapi -@click.argument('color_id', type=int) -@get_or_push_context_obj -def lego_color(api, color_id): - return api.lego_colors_read(id=color_id) +@pass_lego +@get_or_push_context_obj(click.argument('color_id', type=int)) +def lego_color(ctx, color_id): + return ctx.api.lego_colors_read(id=color_id) @add_typed_subcommands(Element) @lego.group('element') -@pass_legoapi -@click.argument('element_id') -@get_or_push_context_obj -def lego_element(api, element_id): - return api.lego_elements_read(element_id=element_id) +@pass_lego +@get_or_push_context_obj(click.argument('element_id')) +def lego_element(ctx, element_id): + return ctx.api.lego_elements_read(element_id=element_id) @add_typed_subcommands(Moc) @lego.group('moc') -@pass_legoapi -@click.argument('set_num') -@get_or_push_context_obj -def lego_moc(api, set_num): - return api.lego_mocs_read(set_num=set_num) +@pass_lego +@get_or_push_context_obj(click.argument('set_num')) +def lego_moc(ctx, set_num): + return ctx.api.lego_mocs_read(set_num=set_num) @lego_moc.command('parts') -@pass_legoapi -@click.pass_context +@pass_lego @object_print -def lego_moc_parts(ctx, api): - moc = ctx.find_object(Moc) - return api.lego_mocs_parts_list(set_num=moc.set_num) +def lego_moc_parts(ctx): + return ctx.api.lego_mocs_parts_list(set_num=ctx.set_num) @lego.command('part_categories') -@pass_legoapi +@pass_lego @object_print -def lego_part_categories(api): - return api.lego_part_categories_list() +def lego_part_categories(ctx): + return ctx.api.lego_part_categories_list() @add_typed_subcommands(PartCategory) @lego.group('part_category') -@pass_legoapi -@click.argument('id', type=int) -@object_print -def lego_part_category(api, id): - return api.lego_part_categories_read(id=id) +@pass_lego +@get_or_push_context_obj(click.argument('id', type=int)) +def lego_part_category(ctx, id): + return ctx.api.lego_part_categories_read(id=id) @lego.command('sets') -@pass_legoapi -def lego_sets(api): - oprint(api.lego_sets_list()) +@pass_lego +def lego_sets(ctx): + oprint(ctx.api.lego_sets_list()) @add_typed_subcommands(Set) @lego.group('set') -@pass_legoapi -@click.argument('set_num') -@get_or_push_context_obj -def lego_set(api, set_num): - return api.lego_sets_read(set_num=set_num) +@pass_lego +@get_or_push_context_obj(click.argument('set_num')) +def lego_set(ctx, set_num): + return ctx.api.lego_sets_read(set_num=set_num) @lego_set.command('parts') -@pass_legoapi -@click.pass_context +@pass_lego @object_print -def lego_set_parts(ctx, api): - set = ctx.find_object(Set) - return api.lego_sets_parts_list(set_num=set.set_num) +def lego_set_parts(ctx): + return ctx.api.lego_sets_parts_list(set_num=ctx.set_num) @lego_set.command('alternates') -@pass_legoapi -@click.pass_context +@pass_lego @object_print -def lego_set_alternates(ctx, api): - set = ctx.find_object(Set) - return api.lego_sets_alternates_list(set_num=set.set_num) +def lego_set_alternates(ctx): + return ctx.api.lego_sets_alternates_list(set_num=ctx.set_num) @lego_set.command('sets') -@pass_legoapi -@click.pass_context +@pass_lego @object_print -def lego_set_sets(ctx, api): - set = ctx.find_object(Set) - return api.lego_sets_sets_list(set_num=set.set_num) +def lego_set_sets(ctx): + return ctx.api.lego_sets_sets_list(set_num=ctx.set_num) @lego.command('themes') -@pass_legoapi +@pass_lego @object_print -def lego_themes(api): - return api.lego_themes_list() +def lego_themes(ctx): + return ctx.api.lego_themes_list() @add_typed_subcommands(Theme) @lego.group('theme') -@pass_legoapi -@click.argument('theme_id') -@get_or_push_context_obj -def lego_theme(api, theme_id): - return api.lego_themes_read(id=theme_id) \ No newline at end of file +@pass_lego +@get_or_push_context_obj(click.argument('theme_id')) +def lego_theme(ctx, theme_id): + return ctx.api.lego_themes_read(id=theme_id) \ No newline at end of file diff --git a/cli/rebrickable_cli/cli/user.py b/cli/rebrickable_cli/cli/user.py index 4caf8e0..a86c66d 100644 --- a/cli/rebrickable_cli/cli/user.py +++ b/cli/rebrickable_cli/cli/user.py @@ -2,7 +2,7 @@ import click -from rebrickable_api import PartList, PartListPart, Profile, SetList, SetListSet, Set, Build +from rebrickable_api import PartList, Profile, SetList, SetListSet, Build from rebrickable_api.rest import ApiException from rebrickable_cli.cli.common import pass_global, get_user_context, add_typed_subcommands, pass_usercontext, \ get_or_push_context_obj, object_print @@ -22,34 +22,29 @@ def user(ctx, global_context, username): @add_typed_subcommands(PartList) @user.group('partlist') -@click.argument('list_id', type=int) @pass_usercontext -@get_or_push_context_obj -def user_partlist(user_context, list_id): - return user_context.api.users_partlists_read(user_token=user_context.token, list_id=list_id) +@get_or_push_context_obj(click.argument('list_id', type=int)) +def user_partlist(ctx, list_id): + return ctx.api.users_partlists_read(user_token=ctx.user_token, list_id=list_id) @user_partlist.command('delete') @pass_usercontext -@click.pass_context @object_print -def user_partlist_delete(ctx, user_context): - partlist = ctx.find_object(PartList) - return user_context.api.users_partlists_delete(user_token=user_context.token, - list_id=partlist.id) +def user_partlist_delete(ctx): + return ctx.api.users_partlists_delete(user_token=ctx.user_token, + list_id=ctx.list_id) @user_partlist.command('partial_update') @pass_usercontext -@click.pass_context @click.option('--name', expose_value=False) @click.option('--is_buildable', expose_value=False, type=bool) @click.option('--num_parts', expose_value=False, type=int) @object_print -def user_partlist_partial_update(ctx, user_context, *args, **kwargs): - partlist = ctx.find_object(PartList) - return user_context.api.users_partlists_partial_update(user_token=user_context.token, - list_id=partlist.id, *args, **kwargs) +def user_partlist_partial_update(ctx, *args, **kwargs): + return ctx.api.users_partlists_partial_update(user_token=ctx.user_token, + list_id=ctx.list_id, *args, **kwargs) @user_partlist.group('parts') @@ -59,93 +54,78 @@ def user_partlist_parts(): @user_partlist_parts.command('create') @pass_usercontext -@click.pass_context @click.argument('part_num') @click.argument('quantity', type=int) @click.argument('color_id', type=int) @object_print -def user_partlist_parts_create(ctx, user_context, part_num, quantity, color_id): - partlist = ctx.find_object(PartList) - return user_context.api.users_partlists_parts_create(user_token=user_context.token, - list_id=partlist.id, - part_num=part_num, - quantity=quantity, - color_id=color_id) +def user_partlist_parts_create(ctx, part_num, quantity, color_id): + return ctx.api.users_partlists_parts_create(user_token=ctx.user_token, + list_id=ctx.list_id, + part_num=part_num, + quantity=quantity, + color_id=color_id) @user_partlist_parts.command('delete') @pass_usercontext -@click.pass_context @click.argument('color_id', type=int) @click.argument('part_num') @object_print -def user_partlist_parts_delete(ctx, user_context, color_id, part_num): - partlist = ctx.find_object(PartList) - return user_context.api.users_partlists_parts_delete(user_token=user_context.token, - color_id=color_id, - list_id=partlist.id, - part_num=part_num) +def user_partlist_parts_delete(ctx, color_id, part_num): + return ctx.api.users_partlists_parts_delete(user_token=ctx.user_token, + color_id=color_id, + list_id=ctx.list_id, + part_num=part_num) @user_partlist_parts.command('list') @pass_usercontext -@click.pass_context @object_print -def user_partlist_parts_list(ctx, user_context): - partlist = ctx.find_object(PartList) - return user_context.api.users_partlists_parts_list(user_token=user_context.token, list_id=partlist.id) +def user_partlist_parts_list(ctx): + return ctx.api.users_partlists_parts_list(user_token=ctx.user_token, list_id=ctx.list_id) @add_typed_subcommands(PartList) @user_partlist.group('part') @pass_usercontext -@click.pass_context -@click.argument('color_id', type=int) -@click.argument('part_num') -@get_or_push_context_obj -def user_partlist_part(ctx, user_context, color_id, part_num): - partlist = ctx.find_object(PartList) - return user_context.api.users_partlists_parts_read(user_token=user_context.token, color_id=color_id, - list_id=partlist.id, - part_num=part_num) +@get_or_push_context_obj(click.argument('part_num'), click.argument('color_id', type=int)) +def user_partlist_part(ctx, color_id, part_num): + return ctx.api.users_partlists_parts_read(user_token=ctx.user_token, color_id=color_id, + list_id=ctx.list_id, + part_num=part_num) @user_partlist_part.command('update') @pass_usercontext -@click.pass_context @click.argument('quantity', type=int) @object_print -def user_partlist_part_update(ctx, user_context, quantity): - partlist = ctx.find_object(PartList) - partlist_part = ctx.find_object(PartListPart) - return user_context.api.users_partlists_parts_update(user_token=user_context.token, color_id=partlist_part.color.id, - list_id=partlist.id, part_num=partlist_part.part.part_num, - quantity=quantity) +def user_partlist_part_update(ctx, quantity): + return ctx.api.users_partlists_parts_update(user_token=ctx.user_token, color_id=ctx.color_id, + list_id=ctx.list_id, part_num=ctx.part_num, + quantity=quantity) @user_partlist.command('update') @pass_usercontext -@click.pass_context @click.argument('name') @object_print -def user_partlist_update(ctx, user_context, name): - partlist = ctx.find_object(PartList) - return user_context.api.users_partlists_update(user_token=user_context.token, list_id=partlist.id, name=name) +def user_partlist_update(ctx, name): + return ctx.api.users_partlists_update(user_token=ctx.user_token, list_id=ctx.list_id, name=name) @user.command('parts') @pass_usercontext @object_print -def user_parts(user_context): - return user_context.api.users_parts_list(user_token=user_context.token) +def user_parts(ctx): + return ctx.api.users_parts_list(user_token=ctx.user_token) @add_typed_subcommands(Profile) @user.group('profile', invoke_without_command=True) @pass_usercontext -@get_or_push_context_obj -def user_profile(user_context): - return user_context.api.users_profile_list(user_token=user_context.token) +@object_print +def user_profile(ctx): + return ctx.api.users_profile_list(user_token=ctx.user_token) @user.group('setlists') @@ -156,34 +136,31 @@ def user_setlists(): @user_setlists.command('list') @pass_usercontext @object_print -def user_setlists_list(user_context): - return user_context.api.users_setlists_list(user_token=user_context.token) +def user_setlists_list(ctx): + return ctx.api.users_setlists_list(user_token=ctx.user_token) @add_typed_subcommands(SetList) @user.group('setlist') -@click.argument('list_id', type=int) @pass_usercontext -@get_or_push_context_obj -def user_setlist(user_context, list_id): - return user_context.api.users_setlists_read(user_token=user_context.token, list_id=list_id) +@get_or_push_context_obj(click.argument('list_id', type=int)) +def user_setlist(ctx, list_id): + return ctx.api.users_setlists_read(user_token=ctx.user_token, list_id=list_id) @user_setlists.command('create') @pass_usercontext @click.argument('name') @object_print -def user_setlists_create(user_context, name): - return user_context.api.users_setlists_create(user_token=user_context.token, name=name) +def user_setlists_create(ctx, name): + return ctx.api.users_setlists_create(user_token=ctx.user_token, name=name) @user_setlist.command('delete') @pass_usercontext -@click.pass_context @object_print -def user_setlist_delete(ctx, user_context): - setlist = ctx.find_object(SetList) - return user_context.api.users_setlists_delete(user_token=user_context.token, list_id=setlist.id) +def user_setlist_delete(ctx): + return ctx.api.users_setlists_delete(user_token=ctx.user_token, list_id=ctx.list_id) @user_setlist.group('partial') @@ -193,62 +170,48 @@ def user_setlists_partial(): @user_setlist.command('update') @pass_usercontext -@click.pass_context @object_print -def user_setlist_partial_update(ctx, user_context): - setlist = ctx.find_object(SetList) - return user_context.api.users_setlists_partial_update(user_token=user_context.token, list_id=setlist.id) +def user_setlist_partial_update(ctx): + return ctx.api.users_setlists_partial_update(user_token=ctx.user_token, list_id=ctx.list_id) @user_setlist.group('sets') -@pass_usercontext -def user_setlist_sets(ctx, user_context): +def user_setlist_sets(): pass @user_setlist_sets.command('list') @pass_usercontext -@click.pass_context @object_print -def user_setlist_sets_list(ctx, user_context): - setlist = ctx.find_object(SetList) - return user_context.api.users_setlists_sets_list(user_token=user_context.token, list_id=setlist.id) +def user_setlist_sets_list(ctx): + return ctx.api.users_setlists_sets_list(user_token=ctx.user_token, list_id=ctx.list_id) @add_typed_subcommands(SetListSet) @user_setlist.group('set') @pass_usercontext -@click.pass_context -@click.argument('set_num') -@get_or_push_context_obj -def user_setlist_set(ctx, user_context, set_num): - setlist = ctx.find_object(SetList) - return user_context.api.users_setlists_sets_read(user_token=user_context.token, list_id=setlist.id, set_num=set_num) +@get_or_push_context_obj(click.argument('set_num')) +def user_setlist_set(ctx, set_num): + return ctx.api.users_setlists_sets_read(user_token=ctx.user_token, list_id=ctx.list_id, set_num=set_num) @user_setlist_sets.command('create') @pass_usercontext -@click.pass_context @click.argument('set_num') @object_print -def user_setlist_sets_create(ctx, user_context, set_num): - setlist = ctx.find_object(SetList) - return user_context.api.users_setlists_sets_create(user_token=user_context.token, - list_id=setlist.id, - set_num=set_num) +def user_setlist_sets_create(ctx, set_num): + return ctx.api.users_setlists_sets_create(user_token=ctx.user_token, + list_id=ctx.list_id, + set_num=set_num) @user_setlist_sets.command('delete') @pass_usercontext -@click.pass_context @object_print -def user_setlist_set_delete(ctx, user_context): - setlist = ctx.find_object(SetList) - setlistset = ctx.find_object(SetListSet) - set_num = setlistset.set.set_num if setlistset.set else setlistset.set_num - return user_context.api.users_setlists_sets_delete(user_token=user_context.token, - list_id=setlist.id, - set_num=set_num) +def user_setlist_set_delete(ctx): + return ctx.api.users_setlists_sets_delete(user_token=ctx.user_token, + list_id=ctx.list_id, + set_num=ctx.set_num) @user_setlist_sets.group() @@ -258,39 +221,31 @@ def user_setlists_sets_partial(): @user_setlists_sets_partial.command('update') @pass_usercontext -@click.pass_context @click.argument('set_num') @object_print -def user_setlist_set_partial_update(ctx, user_context, set_num): - setlist = ctx.find_object(SetList) - return user_context.api.users_setlists_sets_partial_update(user_token=user_context.token, - list_id=setlist.id, - set_num=set_num) +def user_setlist_set_partial_update(ctx, set_num): + return ctx.api.users_setlists_sets_partial_update(user_token=ctx.user_token, + list_id=ctx.list_id, + set_num=set_num) @user_setlist_sets.command('update') @pass_usercontext -@click.pass_context @object_print -def user_setlist_set_update(ctx, user_context): - setlist = ctx.find_object(SetList) - setlistset = ctx.find_object(SetListSet) - set_num = setlistset.set.set_num if setlistset.set else setlistset.set_num - return user_context.api.users_setlists_sets_update(user_token=user_context.token, - list_id=setlist.id, - set_num=set_num) +def user_setlist_set_update(ctx): + return ctx.api.users_setlists_sets_update(user_token=ctx.user_token, + list_id=ctx.list_id, + set_num=ctx.set_num) @user_setlist.command('update') @pass_usercontext -@click.pass_context @click.argument('name') @object_print -def user_setlist_update(ctx, user_context, name): - setlist = ctx.find_object(SetList) - return user_context.api.users_setlists_update(user_token=user_context.token, - list_id=setlist.id, - name=name) +def user_setlist_update(ctx, name): + return ctx.api.users_setlists_update(user_token=ctx.user_token, + list_id=ctx.list_id, + name=name) @user.group('sets') @@ -308,39 +263,36 @@ def user_sets(): @click.option('--max_parts', expose_value=False) @click.option('--search', expose_value=False) @object_print -def user_sets_list(user_context, *args, **kwargs): - return user_context.api.users_sets_list(user_token=user_context.token, *args, **kwargs) +def user_sets_list(ctx, *args, **kwargs): + return ctx.api.users_sets_list(user_token=ctx.user_token, *args, **kwargs) @add_typed_subcommands(SetListSet) @user.group('set') @pass_usercontext -@click.argument('set_num') -@get_or_push_context_obj -def user_set(user_context, set_num): - return user_context.api.users_sets_read(user_token=user_context.token, set_num=set_num) +@get_or_push_context_obj(click.argument('set_num')) +def user_set(ctx, set_num): + return ctx.api.users_sets_read(user_token=ctx.user_token, set_num=set_num) @user_sets.command('create') @pass_usercontext @click.argument('set_num') @object_print -def user_sets_create(user_context, set_num): +def user_sets_create(ctx, set_num): try: - return user_context.api.users_sets_create(user_token=user_context.token, - set_num=set_num) + return ctx.api.users_sets_create(user_token=ctx.user_token, + set_num=set_num) except ApiException as e: print('an error occured: %s, %s, %s' % (e.status, e.body, e.message)) @user_set.command('delete') @pass_usercontext -@click.pass_context @object_print -def user_set_delete(ctx, user_context): - set = ctx.find_object(Set) +def user_set_delete(ctx): try: - return user_context.api.users_sets_delete(user_token=user_context.token, set_num=set.set_num) + return ctx.api.users_sets_delete(user_token=ctx.user_token, set_num=ctx.set_num) except ApiException as e: print('an error occured: %s, %s, %s' % (e.status, e.body, e.message)) @@ -349,39 +301,36 @@ def user_set_delete(ctx, user_context): @pass_usercontext @click.option('--file', '-f', type=click.File('r'), default='-') @object_print -def user_sets_sync(user_context, file): +def user_sets_sync(ctx, file): # Assume the file contains a json list of SetListSet file_content = file.read() array_of_set_list_sets = json.loads(file_content) - return user_context.api.users_sets_sync_create( - user_token=user_context.token, array_of_set_list_sets=array_of_set_list_sets) + return ctx.api.users_sets_sync_create( + user_token=ctx.user_token, array_of_set_list_sets=array_of_set_list_sets) @user_set.command('sync') @pass_usercontext -@click.pass_context @object_print -def user_set_update(ctx, user_context): - set = ctx.find_object(Set) - return user_context.api.users_sets_update( - user_token=user_context.token, set_num=set.set_num) +def user_set_update(ctx): + return ctx.api.users_sets_update( + user_token=ctx.user_token, set_num=ctx.set_num) @user.command('allparts') @pass_usercontext @object_print -def user_allparts(user_context): - return user_context.api.users_allparts_list(user_token=user_context.token) +def user_allparts(ctx): + return ctx.api.users_allparts_list(user_token=ctx.user_token) @add_typed_subcommands(Build) @user.group('build') @pass_usercontext -@click.argument('set_num') -@get_or_push_context_obj -def user_build(user_context, set_num): - return user_context.api.users_build_read(user_token=user_context.token, - set_num=set_num) +@get_or_push_context_obj(click.argument('set_num')) +def user_build(ctx, set_num): + return ctx.api.users_build_read(user_token=ctx.user_token, + set_num=set_num) @user.group('lost_parts') @@ -393,23 +342,23 @@ def user_lost_parts(): @pass_usercontext @click.argument('inv_part_id', type=int) @object_print -def user_lost_parts_create(user_context, inv_part_id): - return user_context.api.users_lost_parts_create(user_token=user_context.token, inv_part_id=inv_part_id) +def user_lost_parts_create(ctx, inv_part_id): + return ctx.api.users_lost_parts_create(user_token=ctx.user_token, inv_part_id=inv_part_id) @user_lost_parts.command('delete') @pass_usercontext @click.argument('lost_part_id', type=int) @object_print -def user_lost_parts_delete(user_context, lost_part_id): - return user_context.api.users_lost_parts_delete(user_token=user_context.token, id=lost_part_id) +def user_lost_parts_delete(ctx, lost_part_id): + return ctx.api.users_lost_parts_delete(user_token=ctx.user_token, id=lost_part_id) @user_lost_parts.command('list') @pass_usercontext @object_print -def user_lost_parts_list(user_context): - return user_context.api.users_lost_parts_list(user_token=user_context.token) +def user_lost_parts_list(ctx): + return ctx.api.users_lost_parts_list(user_token=ctx.user_token) @user.group('partlists') @@ -421,13 +370,13 @@ def user_partlists(): @pass_usercontext @click.argument('name') @object_print -def user_partlists_create(user_context, name): - return user_context.api.users_partlists_create(user_token=user_context.token, - name=name) +def user_partlists_create(ctx, name): + return ctx.api.users_partlists_create(user_token=ctx.user_token, + name=name) @user_partlists.command('list') @pass_usercontext @object_print -def user_partlists_list(user_context): - return user_context.api.users_partlists_list(user_token=user_context.token) \ No newline at end of file +def user_partlists_list(ctx): + return ctx.api.users_partlists_list(user_token=ctx.user_token) diff --git a/cli/rebrickable_cli/cli/users.py b/cli/rebrickable_cli/cli/users.py index 4d95004..b0b8027 100644 --- a/cli/rebrickable_cli/cli/users.py +++ b/cli/rebrickable_cli/cli/users.py @@ -26,8 +26,7 @@ def users_badges_list(api): @add_typed_subcommands(Badge) @users.group('badge') @pass_usersapi -@click.argument('id', type=int) -@get_or_push_context_obj +@get_or_push_context_obj(click.argument('id', type=int)) def users_badge(api, id): return api.users_badges_read(id=id) diff --git a/tests/lego_cli/__init__.py b/tests/lego_cli/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/tests/lego_cli/test_cli.py b/tests/lego_cli/test_cli.py new file mode 100644 index 0000000..ce577ce --- /dev/null +++ b/tests/lego_cli/test_cli.py @@ -0,0 +1,105 @@ +from __future__ import print_function +from rebrickable_api import Set, Part, Color, Moc +from rebrickable_cli.cli.common import GlobalContext, LegoContext +from rebrickable_cli.cli.lego import lego_colors, lego_color, lego_element, lego_part_categories, lego_part_category, \ + lego_parts, lego_sets, lego_themes, lego_theme, lego_set, lego_set_alternates, lego_set_parts, lego_set_sets, \ + lego_part_colors, lego_part, lego_part_color, lego_part_color_sets, lego_moc_parts, lego_moc +from rebrickable_cli.cli.main import OutputFormatter + +from tests.test_cli_integration import parametrized, context_stack, do_test + +lego_operations = [ + (lego_colors, 'lego_colors_list', [], {}), + (lego_color, 'lego_colors_read', ['6'], {'id': 6}), + (lego_element, 'lego_elements_read', ['1234'], {'element_id': '1234'}), + (lego_part_categories, 'lego_part_categories_list', [], {}), + (lego_part_category, 'lego_part_categories_read', ['17859'], {'id': 17859}), + (lego_parts, 'lego_parts_list', [], {}), + (lego_sets, 'lego_sets_list', [], {}), + (lego_themes, 'lego_themes_list', [], {}), + (lego_theme, 'lego_themes_read', ['1485'], {'id': '1485'}), +] + + +@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], lego_operations) +def test_lego_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api): + context = context_stack( + GlobalContext(OutputFormatter(output=print), None), + LegoContext(api=mocked_lego_api) + ) + + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api, context) + + +lego_set_operations = [ + (lego_set, 'lego_sets_read', ['75192-1'], {}), + (lego_set_alternates, 'lego_sets_alternates_list', [], {}), + (lego_set_parts, 'lego_sets_parts_list', [], {}), + (lego_set_sets, 'lego_sets_sets_list', [], {}), +] + + +@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], lego_set_operations) +def test_lego_set_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api): + context = context_stack( + GlobalContext(OutputFormatter(output=print), None), + LegoContext(api=mocked_lego_api, set_num='75192-1') + ) + + call_kwargs['set_num'] = '75192-1' + + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api, context) + + +lego_part_operations = [ + (lego_part_colors, 'lego_parts_colors_list', [], {}), + (lego_part, 'lego_parts_read', ['3004'], {}), +] + + +@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], lego_part_operations) +def test_lego_part_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api): + context = context_stack( + GlobalContext(OutputFormatter(output=print), None), + LegoContext(api=mocked_lego_api, part_num='3004') + ) + + call_kwargs['part_num'] = '3004' + + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api, context) + + +lego_part_color_operations = [ + (lego_part_color, 'lego_parts_colors_read', ['45'], {}), + (lego_part_color_sets, 'lego_parts_colors_sets_list', [], {}), +] + + +@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], lego_part_color_operations) +def test_lego_part_color_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api): + context = context_stack( + GlobalContext(OutputFormatter(output=print), None), + LegoContext(api=mocked_lego_api, part_num='3020', color_id=45) + ) + + call_kwargs['part_num'] = '3020' + call_kwargs['color_id'] = 45 + + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api, context) + + +lego_moc_operations = [ + (lego_moc_parts, 'lego_mocs_parts_list', [], {}), + (lego_moc, 'lego_mocs_read', ['MOC-5634'], {}), +] + + +@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], lego_moc_operations) +def test_lego_moc_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api): + context = context_stack( + GlobalContext(OutputFormatter(output=print), None), + LegoContext(api=mocked_lego_api, set_num='MOC-5634') + ) + call_kwargs['set_num'] = 'MOC-5634' + + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api, context) \ No newline at end of file diff --git a/tests/test_cli.py b/tests/test_cli.py index c019894..f56925d 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -10,7 +10,7 @@ from rebrickable_api import Part, Color, Element, Moc, LegoApi, PartColorsElement from rebrickable_api.rest import ApiException -from rebrickable_cli.cli.common import pass_usercontext, pass_global +from rebrickable_cli.cli.common import pass_usercontext, pass_global, pass_lego from rebrickable_cli.cli.lego import lego, lego_part, lego_part_color, lego_color, lego_element, lego_moc from rebrickable_cli.cli.main import main from rebrickable_cli.cli.user import user @@ -48,17 +48,17 @@ def decorated(*a, **kwa): def with_mocked_api(): - def decorator(fun): - def get_part(part_num, *args, **kwargs): + def wrapper(fun, *args, **kwargs): + def get_part(part_num, *a, **kwa): return Part(part_num=part_num) @wraps(fun) @patch.object(LegoApi, 'lego_parts_read', Mock(side_effect=get_part)) - def wrapper(*args, **kwargs): - return fun(*args, **kwargs) + def wrapper(*a, **kwa): + return fun(*a, **kwa) return wrapper - return decorator + return decorator.decorator(wrapper) @mocked_data({'api_key': 'api_key_value'}) def test_main_command_pass_obj_valid(runner): @@ -74,8 +74,8 @@ def test_main_command_pass_obj_invalid(runner): @user.command(name='test') @pass_usercontext -def user_test(users_context): - assert users_context.token == 'user_token_value' +def user_test(ctx): + assert ctx.user_token == 'user_token_value' @mocked_data({'api_key': 'api_key_value', 'users': {'%%default%%': {'token': 'user_token_value'}}}) @@ -94,10 +94,9 @@ def test_users_command_pass_obj_invalid(runner): @patch.object(LegoApi, 'lego_parts_read', Mock(return_value=Part(part_num='3002'))) def test_lego_part_command_pass_obj(runner): @lego_part.command(name='test') - @click.pass_context + @pass_lego def lego_part_test(ctx): - part = ctx.find_object(Part) - assert part.part_num == "3002" + assert ctx.part_num == "3002" result = runner.invoke(main, ['lego', 'part', '3002', 'test']) assert result.exception is None @@ -108,11 +107,10 @@ def lego_part_test(ctx): @patch.object(LegoApi, 'lego_parts_colors_read', Mock(return_value=PartColorsElement(elements=[Element(color=Color(id=5), part=Part(part_num="3002"))]))) def test_lego_part_color_command_pass_obj(runner): @lego_part_color.command(name='test') - @click.pass_context + @pass_lego def lego_part_color_test(ctx): - part_colors_element = ctx.find_object(PartColorsElement).elements[0] - assert part_colors_element.color.id == 5 - assert part_colors_element.part.part_num == "3002" + assert ctx.color_id == 5 + assert ctx.part_num == "3002" result = runner.invoke(main, ['lego', 'part', '3002', 'color', '5', 'test']) assert result.exception is None @@ -122,10 +120,9 @@ def lego_part_color_test(ctx): @patch.object(LegoApi, 'lego_colors_read', Mock(return_value=Color(id=1234))) def test_lego_color_command_pass_obj(runner): @lego_color.command(name='test') - @click.pass_context + @pass_lego def lego_color_test(ctx): - color = ctx.find_object(Color) - assert color.id == 1234 + assert ctx.color_id == 1234 result = runner.invoke(main, ['lego', 'color', '1234', 'test']) assert result.exception is None @@ -135,10 +132,9 @@ def lego_color_test(ctx): @patch.object(LegoApi, 'lego_elements_read', Mock(return_value=Element(element_id=1234))) def test_lego_element_command_pass_obj(runner): @lego_element.command(name='test') - @click.pass_context + @pass_lego def lego_element_test(ctx): - element = ctx.find_object(Element) - assert element.element_id == 1234 + assert ctx.element_id == '1234' result = runner.invoke(main, ['lego', 'element', '1234', 'test']) assert result.exception is None @@ -148,10 +144,9 @@ def lego_element_test(ctx): @patch.object(LegoApi, 'lego_mocs_read', Mock(return_value = Moc(set_num='MOC-1234'))) def test_lego_moc_command_pass_obj(runner): @lego_moc.command(name='test') - @click.pass_context + @pass_lego def lego_moc_test(ctx): - moc = ctx.find_object(Moc) - assert moc.set_num == "MOC-1234" + assert ctx.set_num == "MOC-1234" result = runner.invoke(main, ['lego', 'moc', 'MOC-1234', 'test']) assert result.exception is None diff --git a/tests/test_cli_integration.py b/tests/test_cli_integration.py index cab18cb..3357be7 100644 --- a/tests/test_cli_integration.py +++ b/tests/test_cli_integration.py @@ -1,6 +1,5 @@ from __future__ import print_function -from rebrickable_api import Set, Part, Color, Moc, PartList, PartListPart, SetList, SetListSet from six import StringIO import pytest @@ -48,103 +47,6 @@ def do_test(cli_func, method, cli_args, call_kwargs, runner, api, context): assert 'stuff\n' == result.output -# legoapi -lego_operations = [ - (lego_colors, 'lego_colors_list', [], {}), - (lego_color, 'lego_colors_read', ['6'], {'id': 6}), - (lego_element, 'lego_elements_read', ['1234'], {'element_id': '1234'}), - (lego_part_categories, 'lego_part_categories_list', [], {}), - (lego_part_category, 'lego_part_categories_read', ['17859'], {'id': 17859}), - (lego_parts, 'lego_parts_list', [], {}), - (lego_sets, 'lego_sets_list', [], {}), - (lego_themes, 'lego_themes_list', [], {}), - (lego_theme, 'lego_themes_read', ['1485'], {'id': '1485'}), -] - - -@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], lego_operations) -def test_lego_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api): - context = context_stack( - GlobalContext(OutputFormatter(output=print), None), - ) - - do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api, context) - - -lego_set_operations = [ - (lego_set, 'lego_sets_read', ['75192-1'], {}), - (lego_set_alternates, 'lego_sets_alternates_list', [], {}), - (lego_set_parts, 'lego_sets_parts_list', [], {}), - (lego_set_sets, 'lego_sets_sets_list', [], {}), -] - -@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], lego_set_operations) -def test_lego_set_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api): - context = context_stack( - GlobalContext(OutputFormatter(output=print), None), - Set(set_num='75192-1') - ) - - call_kwargs['set_num'] = '75192-1' - - do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api, context) - - -lego_part_operations = [ - (lego_part_colors, 'lego_parts_colors_list', [], {}), - (lego_part, 'lego_parts_read', ['3004'], {}), -] - - -@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], lego_part_operations) -def test_lego_part_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api): - context = context_stack( - GlobalContext(OutputFormatter(output=print), None), - Part(part_num='3004') - ) - - call_kwargs['part_num'] = '3004' - - do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api, context) - - -lego_part_color_operations = [ - (lego_part_color, 'lego_parts_colors_read', ['45'], {}), - (lego_part_color_sets, 'lego_parts_colors_sets_list', [], {}), -] - - -@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], lego_part_color_operations) -def test_lego_part_color_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api): - context = context_stack( - GlobalContext(OutputFormatter(output=print), None), - Part(part_num='3020'), - Color(id=45), - ) - - call_kwargs['part_num'] = '3020' - call_kwargs['color_id'] = 45 - - do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api, context) - - -lego_moc_operations = [ - (lego_moc_parts, 'lego_mocs_parts_list', [], {}), - (lego_moc, 'lego_mocs_read', ['MOC-5634'], {}), -] - - -@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], lego_moc_operations) -def test_lego_moc_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api): - context = context_stack( - GlobalContext(OutputFormatter(output=print), None), - Moc(set_num='MOC-5634') - ) - call_kwargs['set_num'] = 'MOC-5634' - - do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api, context) - - users_operations = [ (user_partlists_create, 'users_partlists_create', ['test'], {'name': 'test'}), (user_partlists_list, 'users_partlists_list', [], {}), @@ -171,7 +73,7 @@ def test_lego_moc_entrypoints(cli_func, method, cli_args, call_kwargs, runner, m def test_users_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): context = context_stack( GlobalContext(OutputFormatter(output=print), None), - UserContext(api=mocked_users_api, token='abcdef') + UserContext(api=mocked_users_api, user_token='abcdef') ) call_kwargs['user_token'] = 'abcdef' do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api, context) @@ -187,7 +89,7 @@ def test_users_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mock def test_users_no_token_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): context = context_stack( GlobalContext(OutputFormatter(output=print), None), - UserContext(api=mocked_users_api, token='abcdef') + UserContext(api=mocked_users_api, user_token='abcdef') ) do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api, context) @@ -208,8 +110,7 @@ def test_users_no_token_entrypoints(cli_func, method, cli_args, call_kwargs, run def test_users_partlist_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): context = context_stack( GlobalContext(OutputFormatter(output=print), None), - UserContext(api=mocked_users_api, token='abcdef'), - PartList(id=987654321) + UserContext(api=mocked_users_api, user_token='abcdef', list_id=987654321) ) call_kwargs['list_id'] = 987654321 @@ -230,9 +131,7 @@ def test_users_partlist_entrypoints(cli_func, method, cli_args, call_kwargs, run def test_users_partlist_part_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): context = context_stack( GlobalContext(OutputFormatter(output=print), None), - UserContext(api=mocked_users_api, token='abcdef'), - PartList(id=987654321), - PartListPart(color=Color(id=45), part=Part(part_num='3004')) + UserContext(api=mocked_users_api, user_token='abcdef', list_id=987654321, color_id=45, part_num='3004') ) call_kwargs['color_id'] = 45 call_kwargs['part_num'] = '3004' @@ -256,8 +155,7 @@ def test_users_partlist_part_entrypoints(cli_func, method, cli_args, call_kwargs def test_users_setlist_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): context = context_stack( GlobalContext(OutputFormatter(output=print), None), - UserContext(api=mocked_users_api, token='abcdef'), - SetList(id=987654321) + UserContext(api=mocked_users_api, user_token='abcdef', list_id=987654321), ) call_kwargs['list_id'] = 987654321 @@ -278,9 +176,7 @@ def test_users_setlist_entrypoints(cli_func, method, cli_args, call_kwargs, runn def test_users_setlist_set_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): context = context_stack( GlobalContext(OutputFormatter(output=print), None), - UserContext(api=mocked_users_api, token='abcdef'), - SetList(id=987654321), - SetListSet(set_num='1357-1') + UserContext(api=mocked_users_api, user_token='abcdef', list_id=987654321, set_num='1357-1') ) call_kwargs['list_id'] = 987654321 @@ -301,87 +197,10 @@ def test_users_setlist_set_entrypoints(cli_func, method, cli_args, call_kwargs, def test_users_set_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): context = context_stack( GlobalContext(OutputFormatter(output=print), None), - UserContext(api=mocked_users_api, token='abcdef'), - Set(set_num='75192-1') + UserContext(api=mocked_users_api, user_token='abcdef', set_num='75192-1') ) call_kwargs['set_num'] = '75192-1' call_kwargs['user_token'] = 'abcdef' do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api, context) - -""" - -lego - - colors: - - list - - color: - - read - - element: - - read - - moc: - - read - - parts - - part_categories: - - list - - part_category: - - read - - parts: - - list - - part: - - read - - colors - - color : - - sets - - sets: - - list - - set: - - read - - alternates - - parts - - sets - - themes: - - list - - theme: - - read - -users: - - _token - - badges - - badge - -user - - allparts - - build - - lost_parts: - - list - - lost_part: - - read - - partlists: - - list - - partlist: - - read - - parts: - - list - - part: - - read - - - parts: - - list - - profile: - - read - - setlists: - - list - - setlist: - - read - - sets: - - list - - set: - - read - - sets: - - list - - sync - - set: - - read - -""" \ No newline at end of file diff --git a/tests/test_cli_utils.py b/tests/test_cli_utils.py index 18ecbaa..e21e450 100644 --- a/tests/test_cli_utils.py +++ b/tests/test_cli_utils.py @@ -32,7 +32,7 @@ def test_data(): users_context = get_user_context(api_client) - assert users_context.token == users_token + assert users_context.user_token == users_token assert users_context.api.api_client == api_client diff --git a/tests/test_models_integration.py b/tests/test_models_integration.py index a383535..fe0bb34 100644 --- a/tests/test_models_integration.py +++ b/tests/test_models_integration.py @@ -53,7 +53,7 @@ def remove_nulls(d): ('lego_themes_read', dict(id=99)), ], ids=get_id) @pytest.mark.integration -def test_objects_attributes(func, kwargs, lego_api, api_client): +def test_lego_objects_attributes(func, kwargs, lego_api, api_client): func = getattr(lego_api, func) do_test(func, kwargs, api_client) @@ -68,7 +68,7 @@ def test_objects_attributes(func, kwargs, lego_api, api_client): @pytest.mark.integration def test_objects_attributes(func, kwargs, user_context, api_client): func = getattr(user_context.api, func) - kwargs['user_token'] = user_context.token + kwargs['user_token'] = user_context.user_token do_test(func, kwargs, api_client) From 8d0a4e85ddc468101412adf378c8c618d3c11f80 Mon Sep 17 00:00:00 2001 From: rienafairefr Date: Mon, 10 Sep 2018 00:06:07 +0200 Subject: [PATCH 10/19] same for global context --- cli/rebrickable_cli/cli/common.py | 52 ++++++++++++------- cli/rebrickable_cli/cli/lego.py | 49 +++++++++--------- cli/rebrickable_cli/cli/main.py | 9 ++-- cli/rebrickable_cli/cli/user.py | 86 +++++++++++++++---------------- cli/rebrickable_cli/cli/users.py | 33 ++++++------ tests/lego_cli/test_cli.py | 42 +++++---------- tests/test_cli.py | 16 +++--- tests/test_cli_integration.py | 64 +++++++---------------- tests/test_cli_utils.py | 6 --- tests/test_models_integration.py | 28 +++++----- 10 files changed, 173 insertions(+), 212 deletions(-) diff --git a/cli/rebrickable_cli/cli/common.py b/cli/rebrickable_cli/cli/common.py index 9bd94de..d5502c1 100644 --- a/cli/rebrickable_cli/cli/common.py +++ b/cli/rebrickable_cli/cli/common.py @@ -1,7 +1,7 @@ from functools import wraps import click -from click import get_current_context +from click import get_current_context, Group from rebrickable_api import UsersApi from rebrickable_cli.utils import get_data @@ -25,16 +25,24 @@ def __init__(self, api=None, user_token=None, list_id=None, part_num=None, color self.set_num = set_num -def oprint(obj): - # print an object using the current configured output (json/yaml/py) - get_current_context().find_object(GlobalContext).format.output(obj) - - -class GlobalContext(object): - def __init__(self, format, client): +class State(object): + def __init__(self, format=None, client=None, user_token=None, + list_id=None, part_num=None, color_id=None, set_num=None, api=None): self.format = format self.client = client + self.api = api + self.user_token = user_token + self.list_id = list_id + self.part_num = part_num + self.color_id = color_id + self.set_num = set_num + + +def oprint(obj): + # print an object using the current configured output (json/yaml/py) + get_current_context().find_object(State).format.output(obj) + def get_or_push_context_obj(*decorators): def decorator(fun): @@ -44,10 +52,7 @@ def decorator(fun): def decorated(ctx, obj, *args, **kwargs): for attr in kwargs: setattr(obj, attr, kwargs[attr]) - try: - current_obj = fun(obj, *args, **kwargs) - except: - current_obj = fun(*args, **kwargs) + current_obj = fun(*args, **kwargs) if ctx.invoked_subcommand is None: oprint(current_obj) @@ -86,14 +91,21 @@ def decorator(fun): return decorator -def get_user_context(client, username='%%default%%'): - users_api = UsersApi(client) +def get_user_token(username='%%default%%'): data = get_data() - user_token = data['users'][username]['token'] - return UserContext(users_api, user_token) + return data['users'][username]['token'] + + +pass_state = click.make_pass_decorator(State) + +class StateGroup(Group): + def group(self, *args, **kwargs): + def decorated(fun): + return pass_state(fun) + return super(StateGroup, self).group(*args, **kwargs)(decorated) -pass_global = click.make_pass_decorator(GlobalContext) -pass_lego = click.make_pass_decorator(LegoContext) -pass_usercontext = click.make_pass_decorator(UserContext) -pass_usersapi = click.make_pass_decorator(UsersApi) \ No newline at end of file + def command(self, *args, **kwargs): + def decorated(fun): + return pass_state(fun) + return super(StateGroup, self).command(*args, **kwargs)(decorated) \ No newline at end of file diff --git a/cli/rebrickable_cli/cli/lego.py b/cli/rebrickable_cli/cli/lego.py index 228035c..89885e0 100644 --- a/cli/rebrickable_cli/cli/lego.py +++ b/cli/rebrickable_cli/cli/lego.py @@ -1,19 +1,18 @@ import click from rebrickable_api import LegoApi, Part, PartColorsElement, Color, Element, Moc, PartCategory, Set, Theme -from rebrickable_cli.cli.common import pass_global, add_typed_subcommands, pass_lego, get_or_push_context_obj, \ - object_print, oprint, LegoContext +from rebrickable_cli.cli.common import add_typed_subcommands, pass_state, get_or_push_context_obj, \ + object_print, oprint @click.group(help='LEGO data (parts, sets, themes, etc.)') -@pass_global -@click.pass_context -def lego(ctx, global_context): - ctx.obj = LegoContext(api=LegoApi(global_context.client)) +@pass_state +def lego(ctx): + ctx.api = LegoApi(ctx.client) @lego.command('parts') -@pass_lego +@pass_state @object_print def lego_parts(ctx): return ctx.api.lego_parts_list() @@ -21,14 +20,14 @@ def lego_parts(ctx): @add_typed_subcommands(Part) @lego.group('part') -@pass_lego +@pass_state @get_or_push_context_obj(click.argument('part_num')) def lego_part(ctx, part_num): return ctx.api.lego_parts_read(part_num=ctx.part_num) @lego_part.command('colors') -@pass_lego +@pass_state @object_print def lego_part_colors(ctx): return ctx.api.lego_parts_colors_list(part_num=ctx.part_num) @@ -36,21 +35,21 @@ def lego_part_colors(ctx): @add_typed_subcommands(PartColorsElement) @lego_part.group('color') -@pass_lego +@pass_state @get_or_push_context_obj(click.argument('color_id', type=int)) def lego_part_color(ctx, color_id): return ctx.api.lego_parts_colors_read(color_id=color_id, part_num=ctx.part_num) @lego_part_color.command('sets') -@pass_lego +@pass_state @object_print def lego_part_color_sets(ctx): return ctx.api.lego_parts_colors_sets_list(color_id=ctx.color_id, part_num=ctx.part_num) @lego.command('colors') -@pass_lego +@pass_state @object_print def lego_colors(ctx): return ctx.api.lego_colors_list() @@ -58,7 +57,7 @@ def lego_colors(ctx): @add_typed_subcommands(Color) @lego.group('color') -@pass_lego +@pass_state @get_or_push_context_obj(click.argument('color_id', type=int)) def lego_color(ctx, color_id): return ctx.api.lego_colors_read(id=color_id) @@ -66,7 +65,7 @@ def lego_color(ctx, color_id): @add_typed_subcommands(Element) @lego.group('element') -@pass_lego +@pass_state @get_or_push_context_obj(click.argument('element_id')) def lego_element(ctx, element_id): return ctx.api.lego_elements_read(element_id=element_id) @@ -74,21 +73,21 @@ def lego_element(ctx, element_id): @add_typed_subcommands(Moc) @lego.group('moc') -@pass_lego +@pass_state @get_or_push_context_obj(click.argument('set_num')) def lego_moc(ctx, set_num): return ctx.api.lego_mocs_read(set_num=set_num) @lego_moc.command('parts') -@pass_lego +@pass_state @object_print def lego_moc_parts(ctx): return ctx.api.lego_mocs_parts_list(set_num=ctx.set_num) @lego.command('part_categories') -@pass_lego +@pass_state @object_print def lego_part_categories(ctx): return ctx.api.lego_part_categories_list() @@ -96,49 +95,49 @@ def lego_part_categories(ctx): @add_typed_subcommands(PartCategory) @lego.group('part_category') -@pass_lego +@pass_state @get_or_push_context_obj(click.argument('id', type=int)) def lego_part_category(ctx, id): return ctx.api.lego_part_categories_read(id=id) @lego.command('sets') -@pass_lego +@pass_state def lego_sets(ctx): oprint(ctx.api.lego_sets_list()) @add_typed_subcommands(Set) @lego.group('set') -@pass_lego +@pass_state @get_or_push_context_obj(click.argument('set_num')) def lego_set(ctx, set_num): return ctx.api.lego_sets_read(set_num=set_num) @lego_set.command('parts') -@pass_lego +@pass_state @object_print def lego_set_parts(ctx): return ctx.api.lego_sets_parts_list(set_num=ctx.set_num) @lego_set.command('alternates') -@pass_lego +@pass_state @object_print def lego_set_alternates(ctx): return ctx.api.lego_sets_alternates_list(set_num=ctx.set_num) @lego_set.command('sets') -@pass_lego +@pass_state @object_print def lego_set_sets(ctx): return ctx.api.lego_sets_sets_list(set_num=ctx.set_num) @lego.command('themes') -@pass_lego +@pass_state @object_print def lego_themes(ctx): return ctx.api.lego_themes_list() @@ -146,7 +145,7 @@ def lego_themes(ctx): @add_typed_subcommands(Theme) @lego.group('theme') -@pass_lego +@pass_state @get_or_push_context_obj(click.argument('theme_id')) def lego_theme(ctx, theme_id): return ctx.api.lego_themes_read(id=theme_id) \ No newline at end of file diff --git a/cli/rebrickable_cli/cli/main.py b/cli/rebrickable_cli/cli/main.py index daecf98..779a97d 100644 --- a/cli/rebrickable_cli/cli/main.py +++ b/cli/rebrickable_cli/cli/main.py @@ -11,7 +11,7 @@ from click import get_current_context from rebrickable_api import ApiClient, Configuration -from rebrickable_cli.cli.common import GlobalContext +from rebrickable_cli.cli.common import State from rebrickable_cli.cli.lego import lego from rebrickable_cli.cli.user import user @@ -31,7 +31,6 @@ class OutputFormat(Enum): py = 2 # print - OutputFormatter = namedtuple('OutputFormatter', ['output']) @@ -47,7 +46,7 @@ def get_api_client(): @click.group(help="Rebrickable CLI implemented in Python") @click.pass_context @click.option('--output', '-o', type=EnumType(OutputFormat, casesensitive=False), default="py") -def main(ctx, output): +def main(click_context, output): """Console script for pyrebrickable.""" format = None @@ -59,9 +58,9 @@ def main(ctx, output): format = OutputFormatter(output=lambda o: print(o)) try: - ctx.obj = GlobalContext(format, get_api_client()) + click_context.obj = State(format=format, client=get_api_client()) except (IOError, KeyError, ValueError): - if ctx.invoked_subcommand != 'register': + if click_context.invoked_subcommand != 'register': print('please register your API key using: \nrebrickable register') raise click.Abort() diff --git a/cli/rebrickable_cli/cli/user.py b/cli/rebrickable_cli/cli/user.py index a86c66d..a756593 100644 --- a/cli/rebrickable_cli/cli/user.py +++ b/cli/rebrickable_cli/cli/user.py @@ -2,19 +2,19 @@ import click -from rebrickable_api import PartList, Profile, SetList, SetListSet, Build +from rebrickable_api import PartList, Profile, SetList, SetListSet, Build, UsersApi from rebrickable_api.rest import ApiException -from rebrickable_cli.cli.common import pass_global, get_user_context, add_typed_subcommands, pass_usercontext, \ - get_or_push_context_obj, object_print +from rebrickable_cli.cli.common import add_typed_subcommands, pass_state, \ + get_or_push_context_obj, object_print, get_user_token @click.group(help='user data (sets, parts lists, set lists, etc.)') @click.option('--username', '-u', required=False, default='%%default%%') -@pass_global -@click.pass_context -def user(ctx, global_context, username): +@pass_state +def user(ctx, username): try: - ctx.obj = get_user_context(global_context.client, username) + ctx.api = UsersApi(ctx.client) + ctx.user_token = get_user_token(username) except (IOError, KeyError, ValueError): print('Please login using: \nrebrickable users login [-u username]') raise click.Abort() @@ -22,14 +22,14 @@ def user(ctx, global_context, username): @add_typed_subcommands(PartList) @user.group('partlist') -@pass_usercontext +@pass_state @get_or_push_context_obj(click.argument('list_id', type=int)) def user_partlist(ctx, list_id): return ctx.api.users_partlists_read(user_token=ctx.user_token, list_id=list_id) @user_partlist.command('delete') -@pass_usercontext +@pass_state @object_print def user_partlist_delete(ctx): return ctx.api.users_partlists_delete(user_token=ctx.user_token, @@ -37,7 +37,7 @@ def user_partlist_delete(ctx): @user_partlist.command('partial_update') -@pass_usercontext +@pass_state @click.option('--name', expose_value=False) @click.option('--is_buildable', expose_value=False, type=bool) @click.option('--num_parts', expose_value=False, type=int) @@ -53,7 +53,7 @@ def user_partlist_parts(): @user_partlist_parts.command('create') -@pass_usercontext +@pass_state @click.argument('part_num') @click.argument('quantity', type=int) @click.argument('color_id', type=int) @@ -67,7 +67,7 @@ def user_partlist_parts_create(ctx, part_num, quantity, color_id): @user_partlist_parts.command('delete') -@pass_usercontext +@pass_state @click.argument('color_id', type=int) @click.argument('part_num') @object_print @@ -79,7 +79,7 @@ def user_partlist_parts_delete(ctx, color_id, part_num): @user_partlist_parts.command('list') -@pass_usercontext +@pass_state @object_print def user_partlist_parts_list(ctx): return ctx.api.users_partlists_parts_list(user_token=ctx.user_token, list_id=ctx.list_id) @@ -87,7 +87,7 @@ def user_partlist_parts_list(ctx): @add_typed_subcommands(PartList) @user_partlist.group('part') -@pass_usercontext +@pass_state @get_or_push_context_obj(click.argument('part_num'), click.argument('color_id', type=int)) def user_partlist_part(ctx, color_id, part_num): return ctx.api.users_partlists_parts_read(user_token=ctx.user_token, color_id=color_id, @@ -96,7 +96,7 @@ def user_partlist_part(ctx, color_id, part_num): @user_partlist_part.command('update') -@pass_usercontext +@pass_state @click.argument('quantity', type=int) @object_print def user_partlist_part_update(ctx, quantity): @@ -106,7 +106,7 @@ def user_partlist_part_update(ctx, quantity): @user_partlist.command('update') -@pass_usercontext +@pass_state @click.argument('name') @object_print def user_partlist_update(ctx, name): @@ -114,7 +114,7 @@ def user_partlist_update(ctx, name): @user.command('parts') -@pass_usercontext +@pass_state @object_print def user_parts(ctx): return ctx.api.users_parts_list(user_token=ctx.user_token) @@ -122,7 +122,7 @@ def user_parts(ctx): @add_typed_subcommands(Profile) @user.group('profile', invoke_without_command=True) -@pass_usercontext +@pass_state @object_print def user_profile(ctx): return ctx.api.users_profile_list(user_token=ctx.user_token) @@ -134,7 +134,7 @@ def user_setlists(): @user_setlists.command('list') -@pass_usercontext +@pass_state @object_print def user_setlists_list(ctx): return ctx.api.users_setlists_list(user_token=ctx.user_token) @@ -142,14 +142,14 @@ def user_setlists_list(ctx): @add_typed_subcommands(SetList) @user.group('setlist') -@pass_usercontext +@pass_state @get_or_push_context_obj(click.argument('list_id', type=int)) def user_setlist(ctx, list_id): return ctx.api.users_setlists_read(user_token=ctx.user_token, list_id=list_id) @user_setlists.command('create') -@pass_usercontext +@pass_state @click.argument('name') @object_print def user_setlists_create(ctx, name): @@ -157,7 +157,7 @@ def user_setlists_create(ctx, name): @user_setlist.command('delete') -@pass_usercontext +@pass_state @object_print def user_setlist_delete(ctx): return ctx.api.users_setlists_delete(user_token=ctx.user_token, list_id=ctx.list_id) @@ -169,7 +169,7 @@ def user_setlists_partial(): @user_setlist.command('update') -@pass_usercontext +@pass_state @object_print def user_setlist_partial_update(ctx): return ctx.api.users_setlists_partial_update(user_token=ctx.user_token, list_id=ctx.list_id) @@ -181,7 +181,7 @@ def user_setlist_sets(): @user_setlist_sets.command('list') -@pass_usercontext +@pass_state @object_print def user_setlist_sets_list(ctx): return ctx.api.users_setlists_sets_list(user_token=ctx.user_token, list_id=ctx.list_id) @@ -189,14 +189,14 @@ def user_setlist_sets_list(ctx): @add_typed_subcommands(SetListSet) @user_setlist.group('set') -@pass_usercontext +@pass_state @get_or_push_context_obj(click.argument('set_num')) def user_setlist_set(ctx, set_num): return ctx.api.users_setlists_sets_read(user_token=ctx.user_token, list_id=ctx.list_id, set_num=set_num) @user_setlist_sets.command('create') -@pass_usercontext +@pass_state @click.argument('set_num') @object_print def user_setlist_sets_create(ctx, set_num): @@ -206,7 +206,7 @@ def user_setlist_sets_create(ctx, set_num): @user_setlist_sets.command('delete') -@pass_usercontext +@pass_state @object_print def user_setlist_set_delete(ctx): return ctx.api.users_setlists_sets_delete(user_token=ctx.user_token, @@ -220,7 +220,7 @@ def user_setlists_sets_partial(): @user_setlists_sets_partial.command('update') -@pass_usercontext +@pass_state @click.argument('set_num') @object_print def user_setlist_set_partial_update(ctx, set_num): @@ -230,7 +230,7 @@ def user_setlist_set_partial_update(ctx, set_num): @user_setlist_sets.command('update') -@pass_usercontext +@pass_state @object_print def user_setlist_set_update(ctx): return ctx.api.users_setlists_sets_update(user_token=ctx.user_token, @@ -239,7 +239,7 @@ def user_setlist_set_update(ctx): @user_setlist.command('update') -@pass_usercontext +@pass_state @click.argument('name') @object_print def user_setlist_update(ctx, name): @@ -254,7 +254,7 @@ def user_sets(): @user_sets.command('list') -@pass_usercontext +@pass_state @click.option('--set_num', expose_value=False) @click.option('--theme_id', expose_value=False) @click.option('--min_year', expose_value=False) @@ -269,14 +269,14 @@ def user_sets_list(ctx, *args, **kwargs): @add_typed_subcommands(SetListSet) @user.group('set') -@pass_usercontext +@pass_state @get_or_push_context_obj(click.argument('set_num')) def user_set(ctx, set_num): return ctx.api.users_sets_read(user_token=ctx.user_token, set_num=set_num) @user_sets.command('create') -@pass_usercontext +@pass_state @click.argument('set_num') @object_print def user_sets_create(ctx, set_num): @@ -288,7 +288,7 @@ def user_sets_create(ctx, set_num): @user_set.command('delete') -@pass_usercontext +@pass_state @object_print def user_set_delete(ctx): try: @@ -298,7 +298,7 @@ def user_set_delete(ctx): @user_sets.command('sync') -@pass_usercontext +@pass_state @click.option('--file', '-f', type=click.File('r'), default='-') @object_print def user_sets_sync(ctx, file): @@ -310,7 +310,7 @@ def user_sets_sync(ctx, file): @user_set.command('sync') -@pass_usercontext +@pass_state @object_print def user_set_update(ctx): return ctx.api.users_sets_update( @@ -318,7 +318,7 @@ def user_set_update(ctx): @user.command('allparts') -@pass_usercontext +@pass_state @object_print def user_allparts(ctx): return ctx.api.users_allparts_list(user_token=ctx.user_token) @@ -326,7 +326,7 @@ def user_allparts(ctx): @add_typed_subcommands(Build) @user.group('build') -@pass_usercontext +@pass_state @get_or_push_context_obj(click.argument('set_num')) def user_build(ctx, set_num): return ctx.api.users_build_read(user_token=ctx.user_token, @@ -339,7 +339,7 @@ def user_lost_parts(): @user_lost_parts.command('create') -@pass_usercontext +@pass_state @click.argument('inv_part_id', type=int) @object_print def user_lost_parts_create(ctx, inv_part_id): @@ -347,7 +347,7 @@ def user_lost_parts_create(ctx, inv_part_id): @user_lost_parts.command('delete') -@pass_usercontext +@pass_state @click.argument('lost_part_id', type=int) @object_print def user_lost_parts_delete(ctx, lost_part_id): @@ -355,7 +355,7 @@ def user_lost_parts_delete(ctx, lost_part_id): @user_lost_parts.command('list') -@pass_usercontext +@pass_state @object_print def user_lost_parts_list(ctx): return ctx.api.users_lost_parts_list(user_token=ctx.user_token) @@ -367,7 +367,7 @@ def user_partlists(): @user_partlists.command('create') -@pass_usercontext +@pass_state @click.argument('name') @object_print def user_partlists_create(ctx, name): @@ -376,7 +376,7 @@ def user_partlists_create(ctx, name): @user_partlists.command('list') -@pass_usercontext +@pass_state @object_print def user_partlists_list(ctx): return ctx.api.users_partlists_list(user_token=ctx.user_token) diff --git a/cli/rebrickable_cli/cli/users.py b/cli/rebrickable_cli/cli/users.py index b0b8027..b3341bb 100644 --- a/cli/rebrickable_cli/cli/users.py +++ b/cli/rebrickable_cli/cli/users.py @@ -4,50 +4,49 @@ from rebrickable_api import UsersApi, Badge from rebrickable_api.rest import ApiException -from rebrickable_cli.cli.common import pass_global, pass_usersapi, object_print, add_typed_subcommands, \ - get_or_push_context_obj +from rebrickable_cli.cli.common import object_print, add_typed_subcommands, \ + get_or_push_context_obj, pass_state from rebrickable_cli.utils import get_data, write_data, DATA_PATH @click.group(help='login a certain user or get global badges information') -@pass_global -@click.pass_context -def users(ctx, global_context): - ctx.obj = UsersApi(global_context.client) +@pass_state +def users(ctx): + ctx.api = UsersApi(ctx.client) @users.command(name='badges') -@pass_usersapi +@pass_state @object_print -def users_badges_list(api): - return api.users_badges_list() +def users_badges_list(ctx): + return ctx.api.users_badges_list() @add_typed_subcommands(Badge) @users.group('badge') -@pass_usersapi +@pass_state @get_or_push_context_obj(click.argument('id', type=int)) -def users_badge(api, id): - return api.users_badges_read(id=id) +def users_badge(ctx, id): + return ctx.api.users_badges_read(id=id) -def create_auth(users_api, username=None): +def create_auth(ctx, username=None): if username is None: username = input('Username: ') password = getpass() - return users_api.users_token_create(username, password) + return ctx.api.users_token_create(username, password) @users.command(name='login', help='login a certain user (store its user token)') -@pass_usersapi +@pass_state @click.option('--other', help='login another user and not the default (which will be used by default in "rebrickable user [...]")', is_flag=True, default=False) @click.argument('username', required=False) -def users_login(users_api, other, username=None): +def users_login(ctx, other, username=None): try: - users_token = create_auth(users_api, username) + users_token = create_auth(ctx, username) data = get_data() if not other: data.setdefault('users', {}).setdefault('%%default%%', {})['token'] = users_token diff --git a/tests/lego_cli/test_cli.py b/tests/lego_cli/test_cli.py index ce577ce..b7f6f37 100644 --- a/tests/lego_cli/test_cli.py +++ b/tests/lego_cli/test_cli.py @@ -1,12 +1,12 @@ from __future__ import print_function -from rebrickable_api import Set, Part, Color, Moc -from rebrickable_cli.cli.common import GlobalContext, LegoContext + +from rebrickable_cli.cli.common import State from rebrickable_cli.cli.lego import lego_colors, lego_color, lego_element, lego_part_categories, lego_part_category, \ lego_parts, lego_sets, lego_themes, lego_theme, lego_set, lego_set_alternates, lego_set_parts, lego_set_sets, \ lego_part_colors, lego_part, lego_part_color, lego_part_color_sets, lego_moc_parts, lego_moc from rebrickable_cli.cli.main import OutputFormatter -from tests.test_cli_integration import parametrized, context_stack, do_test +from tests.test_cli_integration import parametrized, do_test lego_operations = [ (lego_colors, 'lego_colors_list', [], {}), @@ -23,12 +23,9 @@ @parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], lego_operations) def test_lego_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api): - context = context_stack( - GlobalContext(OutputFormatter(output=print), None), - LegoContext(api=mocked_lego_api) - ) + state = State(format=OutputFormatter(output=print), api=mocked_lego_api) - do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api, context) + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api, state) lego_set_operations = [ @@ -41,14 +38,11 @@ def test_lego_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocke @parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], lego_set_operations) def test_lego_set_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api): - context = context_stack( - GlobalContext(OutputFormatter(output=print), None), - LegoContext(api=mocked_lego_api, set_num='75192-1') - ) + state = State(format=OutputFormatter(output=print), api=mocked_lego_api, set_num='75192-1') call_kwargs['set_num'] = '75192-1' - do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api, context) + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api, state) lego_part_operations = [ @@ -59,14 +53,11 @@ def test_lego_set_entrypoints(cli_func, method, cli_args, call_kwargs, runner, m @parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], lego_part_operations) def test_lego_part_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api): - context = context_stack( - GlobalContext(OutputFormatter(output=print), None), - LegoContext(api=mocked_lego_api, part_num='3004') - ) + state = State(OutputFormatter(output=print), api=mocked_lego_api, part_num='3004') call_kwargs['part_num'] = '3004' - do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api, context) + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api, state) lego_part_color_operations = [ @@ -77,15 +68,12 @@ def test_lego_part_entrypoints(cli_func, method, cli_args, call_kwargs, runner, @parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], lego_part_color_operations) def test_lego_part_color_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api): - context = context_stack( - GlobalContext(OutputFormatter(output=print), None), - LegoContext(api=mocked_lego_api, part_num='3020', color_id=45) - ) + state = State(format=OutputFormatter(output=print), api=mocked_lego_api, part_num='3020', color_id=45) call_kwargs['part_num'] = '3020' call_kwargs['color_id'] = 45 - do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api, context) + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api, state) lego_moc_operations = [ @@ -96,10 +84,8 @@ def test_lego_part_color_entrypoints(cli_func, method, cli_args, call_kwargs, ru @parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], lego_moc_operations) def test_lego_moc_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api): - context = context_stack( - GlobalContext(OutputFormatter(output=print), None), - LegoContext(api=mocked_lego_api, set_num='MOC-5634') - ) + state = State(format=OutputFormatter(output=print), api=mocked_lego_api, set_num='MOC-5634') + call_kwargs['set_num'] = 'MOC-5634' - do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api, context) \ No newline at end of file + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api, state) diff --git a/tests/test_cli.py b/tests/test_cli.py index f56925d..c026953 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -10,7 +10,7 @@ from rebrickable_api import Part, Color, Element, Moc, LegoApi, PartColorsElement from rebrickable_api.rest import ApiException -from rebrickable_cli.cli.common import pass_usercontext, pass_global, pass_lego +from rebrickable_cli.cli.common import pass_state from rebrickable_cli.cli.lego import lego, lego_part, lego_part_color, lego_color, lego_element, lego_moc from rebrickable_cli.cli.main import main from rebrickable_cli.cli.user import user @@ -27,7 +27,7 @@ def test_command_line_interface(runner): @main.command(name='test') -@pass_global +@pass_state def command_dummy(obj): pass @@ -73,7 +73,7 @@ def test_main_command_pass_obj_invalid(runner): @user.command(name='test') -@pass_usercontext +@pass_state def user_test(ctx): assert ctx.user_token == 'user_token_value' @@ -94,7 +94,7 @@ def test_users_command_pass_obj_invalid(runner): @patch.object(LegoApi, 'lego_parts_read', Mock(return_value=Part(part_num='3002'))) def test_lego_part_command_pass_obj(runner): @lego_part.command(name='test') - @pass_lego + @pass_state def lego_part_test(ctx): assert ctx.part_num == "3002" @@ -107,7 +107,7 @@ def lego_part_test(ctx): @patch.object(LegoApi, 'lego_parts_colors_read', Mock(return_value=PartColorsElement(elements=[Element(color=Color(id=5), part=Part(part_num="3002"))]))) def test_lego_part_color_command_pass_obj(runner): @lego_part_color.command(name='test') - @pass_lego + @pass_state def lego_part_color_test(ctx): assert ctx.color_id == 5 assert ctx.part_num == "3002" @@ -120,7 +120,7 @@ def lego_part_color_test(ctx): @patch.object(LegoApi, 'lego_colors_read', Mock(return_value=Color(id=1234))) def test_lego_color_command_pass_obj(runner): @lego_color.command(name='test') - @pass_lego + @pass_state def lego_color_test(ctx): assert ctx.color_id == 1234 @@ -132,7 +132,7 @@ def lego_color_test(ctx): @patch.object(LegoApi, 'lego_elements_read', Mock(return_value=Element(element_id=1234))) def test_lego_element_command_pass_obj(runner): @lego_element.command(name='test') - @pass_lego + @pass_state def lego_element_test(ctx): assert ctx.element_id == '1234' @@ -144,7 +144,7 @@ def lego_element_test(ctx): @patch.object(LegoApi, 'lego_mocs_read', Mock(return_value = Moc(set_num='MOC-1234'))) def test_lego_moc_command_pass_obj(runner): @lego_moc.command(name='test') - @pass_lego + @pass_state def lego_moc_test(ctx): assert ctx.set_num == "MOC-1234" diff --git a/tests/test_cli_integration.py b/tests/test_cli_integration.py index 3357be7..a1d262d 100644 --- a/tests/test_cli_integration.py +++ b/tests/test_cli_integration.py @@ -26,20 +26,10 @@ def get_id(param): return decorator -def context_stack(*objs): - ctx = None - for obj in objs: - if ctx is None: - ctx = Context(main, obj=obj) - else: - ctx = Context(main, obj=obj, parent=ctx) - return ctx - - def do_test(cli_func, method, cli_args, call_kwargs, runner, api, context): mocked_method = getattr(api, method) mocked_method.return_value = 'stuff' - result = runner.invoke(cli_func, cli_args, obj=api, parent=context) + result = runner.invoke(cli_func, cli_args, obj=context) if result.exit_code != 0: print(result.output) pass @@ -71,12 +61,10 @@ def do_test(cli_func, method, cli_args, call_kwargs, runner, api, context): @parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], users_operations) def test_users_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): - context = context_stack( - GlobalContext(OutputFormatter(output=print), None), - UserContext(api=mocked_users_api, user_token='abcdef') - ) + state = State(format=OutputFormatter(output=print), api=mocked_users_api, user_token='abcdef') + call_kwargs['user_token'] = 'abcdef' - do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api, context) + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api, state) users_no_token_operations = [ @@ -87,11 +75,9 @@ def test_users_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mock @parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], users_no_token_operations) def test_users_no_token_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): - context = context_stack( - GlobalContext(OutputFormatter(output=print), None), - UserContext(api=mocked_users_api, user_token='abcdef') - ) - do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api, context) + state = State(format=OutputFormatter(output=print), api=mocked_users_api, user_token='abcdef') + + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api, state) users_partlist_operations = [ @@ -108,15 +94,12 @@ def test_users_no_token_entrypoints(cli_func, method, cli_args, call_kwargs, run @parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], users_partlist_operations) def test_users_partlist_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): - context = context_stack( - GlobalContext(OutputFormatter(output=print), None), - UserContext(api=mocked_users_api, user_token='abcdef', list_id=987654321) - ) + state = State(format=OutputFormatter(output=print), api=mocked_users_api, user_token='abcdef', list_id=987654321) call_kwargs['list_id'] = 987654321 call_kwargs['user_token'] = 'abcdef' - do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api, context) + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api, state) users_partlist_part_operations = [ @@ -129,16 +112,14 @@ def test_users_partlist_entrypoints(cli_func, method, cli_args, call_kwargs, run @parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], users_partlist_part_operations) def test_users_partlist_part_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): - context = context_stack( - GlobalContext(OutputFormatter(output=print), None), - UserContext(api=mocked_users_api, user_token='abcdef', list_id=987654321, color_id=45, part_num='3004') - ) + state = State(format=OutputFormatter(output=print), api=mocked_users_api, user_token='abcdef', list_id=987654321, color_id=45, part_num='3004') + call_kwargs['color_id'] = 45 call_kwargs['part_num'] = '3004' call_kwargs['list_id'] = 987654321 call_kwargs['user_token'] = 'abcdef' - do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api, context) + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api, state) users_setlist_operations = [ @@ -153,15 +134,12 @@ def test_users_partlist_part_entrypoints(cli_func, method, cli_args, call_kwargs @parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], users_setlist_operations) def test_users_setlist_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): - context = context_stack( - GlobalContext(OutputFormatter(output=print), None), - UserContext(api=mocked_users_api, user_token='abcdef', list_id=987654321), - ) + state = State(format=OutputFormatter(output=print), api=mocked_users_api, user_token='abcdef', list_id=987654321) call_kwargs['list_id'] = 987654321 call_kwargs['user_token'] = 'abcdef' - do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api, context) + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api, state) users_setlist_set_operations = [ @@ -174,16 +152,13 @@ def test_users_setlist_entrypoints(cli_func, method, cli_args, call_kwargs, runn @parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], users_setlist_set_operations) def test_users_setlist_set_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): - context = context_stack( - GlobalContext(OutputFormatter(output=print), None), - UserContext(api=mocked_users_api, user_token='abcdef', list_id=987654321, set_num='1357-1') - ) + state = State(format=OutputFormatter(output=print), api=mocked_users_api, user_token='abcdef', list_id=987654321, set_num='1357-1') call_kwargs['list_id'] = 987654321 call_kwargs['user_token'] = 'abcdef' call_kwargs['set_num'] = '1357-1' - do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api, context) + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api, state) users_set_operations = [ @@ -195,12 +170,9 @@ def test_users_setlist_set_entrypoints(cli_func, method, cli_args, call_kwargs, @parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], users_set_operations) def test_users_set_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): - context = context_stack( - GlobalContext(OutputFormatter(output=print), None), - UserContext(api=mocked_users_api, user_token='abcdef', set_num='75192-1') - ) + state = State(format=OutputFormatter(output=print), api=mocked_users_api, user_token='abcdef', set_num='75192-1') call_kwargs['set_num'] = '75192-1' call_kwargs['user_token'] = 'abcdef' - do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api, context) + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api, state) diff --git a/tests/test_cli_utils.py b/tests/test_cli_utils.py index e21e450..019c9a2 100644 --- a/tests/test_cli_utils.py +++ b/tests/test_cli_utils.py @@ -2,7 +2,6 @@ import mock -from rebrickable_cli.cli.common import get_user_context from rebrickable_cli.cli.main import get_api_client from rebrickable_cli.utils import get_data, write_data @@ -30,11 +29,6 @@ def test_data(): assert api_client.configuration.api_key['Authorization'] == api_key assert api_client.configuration.api_key_prefix['Authorization'] == 'key' - users_context = get_user_context(api_client) - - assert users_context.user_token == users_token - assert users_context.api.api_client == api_client - def test_invalid_data(): m = mock.mock_open(read_data='bla') diff --git a/tests/test_models_integration.py b/tests/test_models_integration.py index fe0bb34..9579748 100644 --- a/tests/test_models_integration.py +++ b/tests/test_models_integration.py @@ -5,8 +5,8 @@ import six from jsondiff import diff -from rebrickable_api import LegoApi, ApiClient -from rebrickable_cli.cli.common import get_user_context +from rebrickable_api import LegoApi, ApiClient, UsersApi +from rebrickable_cli.cli.common import get_user_token, State from rebrickable_cli.cli.main import get_api_client """ @@ -26,8 +26,8 @@ def lego_api(api_client): @pytest.fixture -def user_context(api_client): - return get_user_context(api_client) +def users_context(api_client): + return State(client=api_client, api=UsersApi(api_client), user_token=get_user_token()) def get_id(element): @@ -53,9 +53,9 @@ def remove_nulls(d): ('lego_themes_read', dict(id=99)), ], ids=get_id) @pytest.mark.integration -def test_lego_objects_attributes(func, kwargs, lego_api, api_client): +def test_lego_objects_attributes(func, kwargs, lego_api, users_context): func = getattr(lego_api, func) - do_test(func, kwargs, api_client) + do_test(func, kwargs, users_context) @pytest.mark.parametrize(['func', 'kwargs'], [ @@ -66,19 +66,19 @@ def test_lego_objects_attributes(func, kwargs, lego_api, api_client): ('users_sets_read', dict(set_num='8277-1')), ], ids=get_id) @pytest.mark.integration -def test_objects_attributes(func, kwargs, user_context, api_client): - func = getattr(user_context.api, func) - kwargs['user_token'] = user_context.user_token - do_test(func, kwargs, api_client) +def test_objects_attributes(func, kwargs, users_context): + func = getattr(users_context.api, func) + kwargs['user_token'] = users_context.user_token + do_test(func, kwargs, users_context) @pytest.mark.integration -def test_users_badges_read_attributes(user_context, api_client): - do_test(user_context.api.users_badges_read, dict(id=63), api_client) +def test_users_badges_read_attributes(users_context): + do_test(users_context.api.users_badges_read, dict(id=63), users_context) -def do_test(func, kwargs, api_client): - obj = api_client.sanitize_for_serialization(func(**kwargs)) +def do_test(func, kwargs, ctx): + obj = ctx.client.sanitize_for_serialization(func(**kwargs)) obj_no_preload = json.loads(func(_preload_content=False, **kwargs).data) # ignore Set last_modified_dt (datetime format) From 7e74cb1acca5d73b017da0dc8decea5f598b0509 Mon Sep 17 00:00:00 2001 From: rienafairefr Date: Mon, 10 Sep 2018 16:31:13 +0200 Subject: [PATCH 11/19] move get_user_token to user --- cli/rebrickable_cli/cli/common.py | 6 ------ cli/rebrickable_cli/cli/user.py | 8 +++++++- tests/test_models_integration.py | 3 ++- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/cli/rebrickable_cli/cli/common.py b/cli/rebrickable_cli/cli/common.py index d5502c1..24874df 100644 --- a/cli/rebrickable_cli/cli/common.py +++ b/cli/rebrickable_cli/cli/common.py @@ -4,7 +4,6 @@ from click import get_current_context, Group from rebrickable_api import UsersApi -from rebrickable_cli.utils import get_data class LegoContext(object): @@ -91,11 +90,6 @@ def decorator(fun): return decorator -def get_user_token(username='%%default%%'): - data = get_data() - return data['users'][username]['token'] - - pass_state = click.make_pass_decorator(State) diff --git a/cli/rebrickable_cli/cli/user.py b/cli/rebrickable_cli/cli/user.py index a756593..c3e006f 100644 --- a/cli/rebrickable_cli/cli/user.py +++ b/cli/rebrickable_cli/cli/user.py @@ -5,7 +5,8 @@ from rebrickable_api import PartList, Profile, SetList, SetListSet, Build, UsersApi from rebrickable_api.rest import ApiException from rebrickable_cli.cli.common import add_typed_subcommands, pass_state, \ - get_or_push_context_obj, object_print, get_user_token + get_or_push_context_obj, object_print +from rebrickable_cli.utils import get_data @click.group(help='user data (sets, parts lists, set lists, etc.)') @@ -380,3 +381,8 @@ def user_partlists_create(ctx, name): @object_print def user_partlists_list(ctx): return ctx.api.users_partlists_list(user_token=ctx.user_token) + + +def get_user_token(username='%%default%%'): + data = get_data() + return data['users'][username]['token'] \ No newline at end of file diff --git a/tests/test_models_integration.py b/tests/test_models_integration.py index 9579748..9dff1a0 100644 --- a/tests/test_models_integration.py +++ b/tests/test_models_integration.py @@ -6,7 +6,8 @@ from jsondiff import diff from rebrickable_api import LegoApi, ApiClient, UsersApi -from rebrickable_cli.cli.common import get_user_token, State +from rebrickable_cli.cli.common import State +from rebrickable_cli.cli.user import get_user_token from rebrickable_cli.cli.main import get_api_client """ From eb5f8a9725c1a528a7b71ce0f5d2fed73ea23f8e Mon Sep 17 00:00:00 2001 From: rienafairefr Date: Mon, 10 Sep 2018 16:31:50 +0200 Subject: [PATCH 12/19] remove Lego/User Context --- cli/rebrickable_cli/cli/common.py | 20 -------------------- tests/test_cli_integration.py | 1 - 2 files changed, 21 deletions(-) diff --git a/cli/rebrickable_cli/cli/common.py b/cli/rebrickable_cli/cli/common.py index 24874df..b427596 100644 --- a/cli/rebrickable_cli/cli/common.py +++ b/cli/rebrickable_cli/cli/common.py @@ -3,26 +3,6 @@ import click from click import get_current_context, Group -from rebrickable_api import UsersApi - - -class LegoContext(object): - def __init__(self, api=None, part_num=None, set_num=None, color_id=None): - self.api = api - self.part_num = part_num - self.set_num = set_num - self.color_id = color_id - - -class UserContext(object): - def __init__(self, api=None, user_token=None, list_id=None, part_num=None, color_id=None, set_num=None): - self.api = api - self.user_token = user_token - self.list_id = list_id - self.part_num = part_num - self.color_id = color_id - self.set_num = set_num - class State(object): def __init__(self, format=None, client=None, user_token=None, diff --git a/tests/test_cli_integration.py b/tests/test_cli_integration.py index a1d262d..ea588af 100644 --- a/tests/test_cli_integration.py +++ b/tests/test_cli_integration.py @@ -5,7 +5,6 @@ import pytest from click import Context, Command -from rebrickable_cli.cli.common import UserContext from rebrickable_cli.cli.lego import * from rebrickable_cli.cli.main import * from rebrickable_cli.cli.user import * From c5b6e0763de717ed3f9277651d3c400d41ce57ef Mon Sep 17 00:00:00 2001 From: rienafairefr Date: Mon, 10 Sep 2018 16:31:57 +0200 Subject: [PATCH 13/19] fix get_or_push_context_obj --- cli/rebrickable_cli/cli/common.py | 19 ++++++++++++------- cli/rebrickable_cli/cli/main.py | 2 +- tests/test_cli.py | 1 - 3 files changed, 13 insertions(+), 9 deletions(-) diff --git a/cli/rebrickable_cli/cli/common.py b/cli/rebrickable_cli/cli/common.py index b427596..aca0b35 100644 --- a/cli/rebrickable_cli/cli/common.py +++ b/cli/rebrickable_cli/cli/common.py @@ -1,6 +1,7 @@ from functools import wraps import click +import decorator from click import get_current_context, Group @@ -25,15 +26,20 @@ def oprint(obj): def get_or_push_context_obj(*decorators): def decorator(fun): - @click.pass_obj + @pass_state @click.pass_context @wraps(fun) - def decorated(ctx, obj, *args, **kwargs): + def decorated(ctx, state, *args, **kwargs): for attr in kwargs: - setattr(obj, attr, kwargs[attr]) - current_obj = fun(*args, **kwargs) + setattr(state, attr, kwargs[attr]) + try: + current_obj = fun(*args, **kwargs) + except: + current_obj = fun(state, *args, **kwargs) if ctx.invoked_subcommand is None: oprint(current_obj) + else: + ctx.obj = current_obj current = decorated for dec in decorators: @@ -44,12 +50,11 @@ def decorated(ctx, obj, *args, **kwargs): def object_print(fun): - @wraps(fun) - def decorated(*args, **kwargs): + def object_print_decorator(fun, *args, **kwargs): obj = fun(*args, **kwargs) oprint(obj) - return decorated + return decorator.decorate(fun, object_print_decorator) def add_typed_subcommands(type_): diff --git a/cli/rebrickable_cli/cli/main.py b/cli/rebrickable_cli/cli/main.py index 779a97d..96ab99d 100644 --- a/cli/rebrickable_cli/cli/main.py +++ b/cli/rebrickable_cli/cli/main.py @@ -45,7 +45,7 @@ def get_api_client(): @click.group(help="Rebrickable CLI implemented in Python") @click.pass_context -@click.option('--output', '-o', type=EnumType(OutputFormat, casesensitive=False), default="py") +@click.option('--output', '-o', help='output printer (json, yaml, py --regular print Python function--)',type=EnumType(OutputFormat, casesensitive=False), default="py") def main(click_context, output): """Console script for pyrebrickable.""" diff --git a/tests/test_cli.py b/tests/test_cli.py index c026953..bd075df 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -4,7 +4,6 @@ """Tests for `pyrebrickable` package.""" import decorator -import click from mock import patch, Mock from functools import wraps From 941f7921e52567f4d09493a4d2827ff95ca6bb33 Mon Sep 17 00:00:00 2001 From: rienafairefr Date: Mon, 10 Sep 2018 16:34:44 +0200 Subject: [PATCH 14/19] rename arguments ctx to state where appropriate --- cli/rebrickable_cli/cli/common.py | 6 +- cli/rebrickable_cli/cli/lego.py | 80 ++++++------- cli/rebrickable_cli/cli/user.py | 180 +++++++++++++++--------------- cli/rebrickable_cli/cli/users.py | 20 ++-- cli/rebrickable_cli/utils.py | 4 +- tests/conftest.py | 8 +- tests/test_cli.py | 26 ++--- tests/test_models_integration.py | 4 +- 8 files changed, 164 insertions(+), 164 deletions(-) diff --git a/cli/rebrickable_cli/cli/common.py b/cli/rebrickable_cli/cli/common.py index aca0b35..d5a7d62 100644 --- a/cli/rebrickable_cli/cli/common.py +++ b/cli/rebrickable_cli/cli/common.py @@ -29,17 +29,17 @@ def decorator(fun): @pass_state @click.pass_context @wraps(fun) - def decorated(ctx, state, *args, **kwargs): + def decorated(click_context, state, *args, **kwargs): for attr in kwargs: setattr(state, attr, kwargs[attr]) try: current_obj = fun(*args, **kwargs) except: current_obj = fun(state, *args, **kwargs) - if ctx.invoked_subcommand is None: + if click_context.invoked_subcommand is None: oprint(current_obj) else: - ctx.obj = current_obj + click_context.obj = current_obj current = decorated for dec in decorators: diff --git a/cli/rebrickable_cli/cli/lego.py b/cli/rebrickable_cli/cli/lego.py index 89885e0..15634b1 100644 --- a/cli/rebrickable_cli/cli/lego.py +++ b/cli/rebrickable_cli/cli/lego.py @@ -7,145 +7,145 @@ @click.group(help='LEGO data (parts, sets, themes, etc.)') @pass_state -def lego(ctx): - ctx.api = LegoApi(ctx.client) +def lego(state): + state.api = LegoApi(state.client) @lego.command('parts') @pass_state @object_print -def lego_parts(ctx): - return ctx.api.lego_parts_list() +def lego_parts(state): + return state.api.lego_parts_list() @add_typed_subcommands(Part) @lego.group('part') @pass_state @get_or_push_context_obj(click.argument('part_num')) -def lego_part(ctx, part_num): - return ctx.api.lego_parts_read(part_num=ctx.part_num) +def lego_part(state, part_num): + return state.api.lego_parts_read(part_num=state.part_num) @lego_part.command('colors') @pass_state @object_print -def lego_part_colors(ctx): - return ctx.api.lego_parts_colors_list(part_num=ctx.part_num) +def lego_part_colors(state): + return state.api.lego_parts_colors_list(part_num=state.part_num) @add_typed_subcommands(PartColorsElement) @lego_part.group('color') @pass_state @get_or_push_context_obj(click.argument('color_id', type=int)) -def lego_part_color(ctx, color_id): - return ctx.api.lego_parts_colors_read(color_id=color_id, part_num=ctx.part_num) +def lego_part_color(state, color_id): + return state.api.lego_parts_colors_read(color_id=color_id, part_num=state.part_num) @lego_part_color.command('sets') @pass_state @object_print -def lego_part_color_sets(ctx): - return ctx.api.lego_parts_colors_sets_list(color_id=ctx.color_id, part_num=ctx.part_num) +def lego_part_color_sets(state): + return state.api.lego_parts_colors_sets_list(color_id=state.color_id, part_num=state.part_num) @lego.command('colors') @pass_state @object_print -def lego_colors(ctx): - return ctx.api.lego_colors_list() +def lego_colors(state): + return state.api.lego_colors_list() @add_typed_subcommands(Color) @lego.group('color') @pass_state @get_or_push_context_obj(click.argument('color_id', type=int)) -def lego_color(ctx, color_id): - return ctx.api.lego_colors_read(id=color_id) +def lego_color(state, color_id): + return state.api.lego_colors_read(id=color_id) @add_typed_subcommands(Element) @lego.group('element') @pass_state @get_or_push_context_obj(click.argument('element_id')) -def lego_element(ctx, element_id): - return ctx.api.lego_elements_read(element_id=element_id) +def lego_element(state, element_id): + return state.api.lego_elements_read(element_id=element_id) @add_typed_subcommands(Moc) @lego.group('moc') @pass_state @get_or_push_context_obj(click.argument('set_num')) -def lego_moc(ctx, set_num): - return ctx.api.lego_mocs_read(set_num=set_num) +def lego_moc(state, set_num): + return state.api.lego_mocs_read(set_num=set_num) @lego_moc.command('parts') @pass_state @object_print -def lego_moc_parts(ctx): - return ctx.api.lego_mocs_parts_list(set_num=ctx.set_num) +def lego_moc_parts(state): + return state.api.lego_mocs_parts_list(set_num=state.set_num) @lego.command('part_categories') @pass_state @object_print -def lego_part_categories(ctx): - return ctx.api.lego_part_categories_list() +def lego_part_categories(state): + return state.api.lego_part_categories_list() @add_typed_subcommands(PartCategory) @lego.group('part_category') @pass_state @get_or_push_context_obj(click.argument('id', type=int)) -def lego_part_category(ctx, id): - return ctx.api.lego_part_categories_read(id=id) +def lego_part_category(state, id): + return state.api.lego_part_categories_read(id=id) @lego.command('sets') @pass_state -def lego_sets(ctx): - oprint(ctx.api.lego_sets_list()) +def lego_sets(state): + oprint(state.api.lego_sets_list()) @add_typed_subcommands(Set) @lego.group('set') @pass_state @get_or_push_context_obj(click.argument('set_num')) -def lego_set(ctx, set_num): - return ctx.api.lego_sets_read(set_num=set_num) +def lego_set(state, set_num): + return state.api.lego_sets_read(set_num=set_num) @lego_set.command('parts') @pass_state @object_print -def lego_set_parts(ctx): - return ctx.api.lego_sets_parts_list(set_num=ctx.set_num) +def lego_set_parts(state): + return state.api.lego_sets_parts_list(set_num=state.set_num) @lego_set.command('alternates') @pass_state @object_print -def lego_set_alternates(ctx): - return ctx.api.lego_sets_alternates_list(set_num=ctx.set_num) +def lego_set_alternates(state): + return state.api.lego_sets_alternates_list(set_num=state.set_num) @lego_set.command('sets') @pass_state @object_print -def lego_set_sets(ctx): - return ctx.api.lego_sets_sets_list(set_num=ctx.set_num) +def lego_set_sets(state): + return state.api.lego_sets_sets_list(set_num=state.set_num) @lego.command('themes') @pass_state @object_print -def lego_themes(ctx): - return ctx.api.lego_themes_list() +def lego_themes(state): + return state.api.lego_themes_list() @add_typed_subcommands(Theme) @lego.group('theme') @pass_state @get_or_push_context_obj(click.argument('theme_id')) -def lego_theme(ctx, theme_id): - return ctx.api.lego_themes_read(id=theme_id) \ No newline at end of file +def lego_theme(state, theme_id): + return state.api.lego_themes_read(id=theme_id) \ No newline at end of file diff --git a/cli/rebrickable_cli/cli/user.py b/cli/rebrickable_cli/cli/user.py index c3e006f..883ec2a 100644 --- a/cli/rebrickable_cli/cli/user.py +++ b/cli/rebrickable_cli/cli/user.py @@ -12,10 +12,10 @@ @click.group(help='user data (sets, parts lists, set lists, etc.)') @click.option('--username', '-u', required=False, default='%%default%%') @pass_state -def user(ctx, username): +def user(state, username): try: - ctx.api = UsersApi(ctx.client) - ctx.user_token = get_user_token(username) + state.api = UsersApi(state.client) + state.user_token = get_user_token(username) except (IOError, KeyError, ValueError): print('Please login using: \nrebrickable users login [-u username]') raise click.Abort() @@ -25,16 +25,16 @@ def user(ctx, username): @user.group('partlist') @pass_state @get_or_push_context_obj(click.argument('list_id', type=int)) -def user_partlist(ctx, list_id): - return ctx.api.users_partlists_read(user_token=ctx.user_token, list_id=list_id) +def user_partlist(state, list_id): + return state.api.users_partlists_read(user_token=state.user_token, list_id=list_id) @user_partlist.command('delete') @pass_state @object_print -def user_partlist_delete(ctx): - return ctx.api.users_partlists_delete(user_token=ctx.user_token, - list_id=ctx.list_id) +def user_partlist_delete(state): + return state.api.users_partlists_delete(user_token=state.user_token, + list_id=state.list_id) @user_partlist.command('partial_update') @@ -43,9 +43,9 @@ def user_partlist_delete(ctx): @click.option('--is_buildable', expose_value=False, type=bool) @click.option('--num_parts', expose_value=False, type=int) @object_print -def user_partlist_partial_update(ctx, *args, **kwargs): - return ctx.api.users_partlists_partial_update(user_token=ctx.user_token, - list_id=ctx.list_id, *args, **kwargs) +def user_partlist_partial_update(state, *args, **kwargs): + return state.api.users_partlists_partial_update(user_token=state.user_token, + list_id=state.list_id, *args, **kwargs) @user_partlist.group('parts') @@ -59,9 +59,9 @@ def user_partlist_parts(): @click.argument('quantity', type=int) @click.argument('color_id', type=int) @object_print -def user_partlist_parts_create(ctx, part_num, quantity, color_id): - return ctx.api.users_partlists_parts_create(user_token=ctx.user_token, - list_id=ctx.list_id, +def user_partlist_parts_create(state, part_num, quantity, color_id): + return state.api.users_partlists_parts_create(user_token=state.user_token, + list_id=state.list_id, part_num=part_num, quantity=quantity, color_id=color_id) @@ -72,27 +72,27 @@ def user_partlist_parts_create(ctx, part_num, quantity, color_id): @click.argument('color_id', type=int) @click.argument('part_num') @object_print -def user_partlist_parts_delete(ctx, color_id, part_num): - return ctx.api.users_partlists_parts_delete(user_token=ctx.user_token, +def user_partlist_parts_delete(state, color_id, part_num): + return state.api.users_partlists_parts_delete(user_token=state.user_token, color_id=color_id, - list_id=ctx.list_id, + list_id=state.list_id, part_num=part_num) @user_partlist_parts.command('list') @pass_state @object_print -def user_partlist_parts_list(ctx): - return ctx.api.users_partlists_parts_list(user_token=ctx.user_token, list_id=ctx.list_id) +def user_partlist_parts_list(state): + return state.api.users_partlists_parts_list(user_token=state.user_token, list_id=state.list_id) @add_typed_subcommands(PartList) @user_partlist.group('part') @pass_state @get_or_push_context_obj(click.argument('part_num'), click.argument('color_id', type=int)) -def user_partlist_part(ctx, color_id, part_num): - return ctx.api.users_partlists_parts_read(user_token=ctx.user_token, color_id=color_id, - list_id=ctx.list_id, +def user_partlist_part(state, color_id, part_num): + return state.api.users_partlists_parts_read(user_token=state.user_token, color_id=color_id, + list_id=state.list_id, part_num=part_num) @@ -100,9 +100,9 @@ def user_partlist_part(ctx, color_id, part_num): @pass_state @click.argument('quantity', type=int) @object_print -def user_partlist_part_update(ctx, quantity): - return ctx.api.users_partlists_parts_update(user_token=ctx.user_token, color_id=ctx.color_id, - list_id=ctx.list_id, part_num=ctx.part_num, +def user_partlist_part_update(state, quantity): + return state.api.users_partlists_parts_update(user_token=state.user_token, color_id=state.color_id, + list_id=state.list_id, part_num=state.part_num, quantity=quantity) @@ -110,23 +110,23 @@ def user_partlist_part_update(ctx, quantity): @pass_state @click.argument('name') @object_print -def user_partlist_update(ctx, name): - return ctx.api.users_partlists_update(user_token=ctx.user_token, list_id=ctx.list_id, name=name) +def user_partlist_update(state, name): + return state.api.users_partlists_update(user_token=state.user_token, list_id=state.list_id, name=name) @user.command('parts') @pass_state @object_print -def user_parts(ctx): - return ctx.api.users_parts_list(user_token=ctx.user_token) +def user_parts(state): + return state.api.users_parts_list(user_token=state.user_token) @add_typed_subcommands(Profile) @user.group('profile', invoke_without_command=True) @pass_state @object_print -def user_profile(ctx): - return ctx.api.users_profile_list(user_token=ctx.user_token) +def user_profile(state): + return state.api.users_profile_list(user_token=state.user_token) @user.group('setlists') @@ -137,31 +137,31 @@ def user_setlists(): @user_setlists.command('list') @pass_state @object_print -def user_setlists_list(ctx): - return ctx.api.users_setlists_list(user_token=ctx.user_token) +def user_setlists_list(state): + return state.api.users_setlists_list(user_token=state.user_token) @add_typed_subcommands(SetList) @user.group('setlist') @pass_state @get_or_push_context_obj(click.argument('list_id', type=int)) -def user_setlist(ctx, list_id): - return ctx.api.users_setlists_read(user_token=ctx.user_token, list_id=list_id) +def user_setlist(state, list_id): + return state.api.users_setlists_read(user_token=state.user_token, list_id=list_id) @user_setlists.command('create') @pass_state @click.argument('name') @object_print -def user_setlists_create(ctx, name): - return ctx.api.users_setlists_create(user_token=ctx.user_token, name=name) +def user_setlists_create(state, name): + return state.api.users_setlists_create(user_token=state.user_token, name=name) @user_setlist.command('delete') @pass_state @object_print -def user_setlist_delete(ctx): - return ctx.api.users_setlists_delete(user_token=ctx.user_token, list_id=ctx.list_id) +def user_setlist_delete(state): + return state.api.users_setlists_delete(user_token=state.user_token, list_id=state.list_id) @user_setlist.group('partial') @@ -172,8 +172,8 @@ def user_setlists_partial(): @user_setlist.command('update') @pass_state @object_print -def user_setlist_partial_update(ctx): - return ctx.api.users_setlists_partial_update(user_token=ctx.user_token, list_id=ctx.list_id) +def user_setlist_partial_update(state): + return state.api.users_setlists_partial_update(user_token=state.user_token, list_id=state.list_id) @user_setlist.group('sets') @@ -184,35 +184,35 @@ def user_setlist_sets(): @user_setlist_sets.command('list') @pass_state @object_print -def user_setlist_sets_list(ctx): - return ctx.api.users_setlists_sets_list(user_token=ctx.user_token, list_id=ctx.list_id) +def user_setlist_sets_list(state): + return state.api.users_setlists_sets_list(user_token=state.user_token, list_id=state.list_id) @add_typed_subcommands(SetListSet) @user_setlist.group('set') @pass_state @get_or_push_context_obj(click.argument('set_num')) -def user_setlist_set(ctx, set_num): - return ctx.api.users_setlists_sets_read(user_token=ctx.user_token, list_id=ctx.list_id, set_num=set_num) +def user_setlist_set(state, set_num): + return state.api.users_setlists_sets_read(user_token=state.user_token, list_id=state.list_id, set_num=set_num) @user_setlist_sets.command('create') @pass_state @click.argument('set_num') @object_print -def user_setlist_sets_create(ctx, set_num): - return ctx.api.users_setlists_sets_create(user_token=ctx.user_token, - list_id=ctx.list_id, +def user_setlist_sets_create(state, set_num): + return state.api.users_setlists_sets_create(user_token=state.user_token, + list_id=state.list_id, set_num=set_num) @user_setlist_sets.command('delete') @pass_state @object_print -def user_setlist_set_delete(ctx): - return ctx.api.users_setlists_sets_delete(user_token=ctx.user_token, - list_id=ctx.list_id, - set_num=ctx.set_num) +def user_setlist_set_delete(state): + return state.api.users_setlists_sets_delete(user_token=state.user_token, + list_id=state.list_id, + set_num=state.set_num) @user_setlist_sets.group() @@ -224,28 +224,28 @@ def user_setlists_sets_partial(): @pass_state @click.argument('set_num') @object_print -def user_setlist_set_partial_update(ctx, set_num): - return ctx.api.users_setlists_sets_partial_update(user_token=ctx.user_token, - list_id=ctx.list_id, +def user_setlist_set_partial_update(state, set_num): + return state.api.users_setlists_sets_partial_update(user_token=state.user_token, + list_id=state.list_id, set_num=set_num) @user_setlist_sets.command('update') @pass_state @object_print -def user_setlist_set_update(ctx): - return ctx.api.users_setlists_sets_update(user_token=ctx.user_token, - list_id=ctx.list_id, - set_num=ctx.set_num) +def user_setlist_set_update(state): + return state.api.users_setlists_sets_update(user_token=state.user_token, + list_id=state.list_id, + set_num=state.set_num) @user_setlist.command('update') @pass_state @click.argument('name') @object_print -def user_setlist_update(ctx, name): - return ctx.api.users_setlists_update(user_token=ctx.user_token, - list_id=ctx.list_id, +def user_setlist_update(state, name): + return state.api.users_setlists_update(user_token=state.user_token, + list_id=state.list_id, name=name) @@ -264,25 +264,25 @@ def user_sets(): @click.option('--max_parts', expose_value=False) @click.option('--search', expose_value=False) @object_print -def user_sets_list(ctx, *args, **kwargs): - return ctx.api.users_sets_list(user_token=ctx.user_token, *args, **kwargs) +def user_sets_list(state, *args, **kwargs): + return state.api.users_sets_list(user_token=state.user_token, *args, **kwargs) @add_typed_subcommands(SetListSet) @user.group('set') @pass_state @get_or_push_context_obj(click.argument('set_num')) -def user_set(ctx, set_num): - return ctx.api.users_sets_read(user_token=ctx.user_token, set_num=set_num) +def user_set(state, set_num): + return state.api.users_sets_read(user_token=state.user_token, set_num=set_num) @user_sets.command('create') @pass_state @click.argument('set_num') @object_print -def user_sets_create(ctx, set_num): +def user_sets_create(state, set_num): try: - return ctx.api.users_sets_create(user_token=ctx.user_token, + return state.api.users_sets_create(user_token=state.user_token, set_num=set_num) except ApiException as e: print('an error occured: %s, %s, %s' % (e.status, e.body, e.message)) @@ -291,9 +291,9 @@ def user_sets_create(ctx, set_num): @user_set.command('delete') @pass_state @object_print -def user_set_delete(ctx): +def user_set_delete(state): try: - return ctx.api.users_sets_delete(user_token=ctx.user_token, set_num=ctx.set_num) + return state.api.users_sets_delete(user_token=state.user_token, set_num=state.set_num) except ApiException as e: print('an error occured: %s, %s, %s' % (e.status, e.body, e.message)) @@ -302,35 +302,35 @@ def user_set_delete(ctx): @pass_state @click.option('--file', '-f', type=click.File('r'), default='-') @object_print -def user_sets_sync(ctx, file): +def user_sets_sync(state, file): # Assume the file contains a json list of SetListSet file_content = file.read() array_of_set_list_sets = json.loads(file_content) - return ctx.api.users_sets_sync_create( - user_token=ctx.user_token, array_of_set_list_sets=array_of_set_list_sets) + return state.api.users_sets_sync_create( + user_token=state.user_token, array_of_set_list_sets=array_of_set_list_sets) @user_set.command('sync') @pass_state @object_print -def user_set_update(ctx): - return ctx.api.users_sets_update( - user_token=ctx.user_token, set_num=ctx.set_num) +def user_set_update(state): + return state.api.users_sets_update( + user_token=state.user_token, set_num=state.set_num) @user.command('allparts') @pass_state @object_print -def user_allparts(ctx): - return ctx.api.users_allparts_list(user_token=ctx.user_token) +def user_allparts(state): + return state.api.users_allparts_list(user_token=state.user_token) @add_typed_subcommands(Build) @user.group('build') @pass_state @get_or_push_context_obj(click.argument('set_num')) -def user_build(ctx, set_num): - return ctx.api.users_build_read(user_token=ctx.user_token, +def user_build(state, set_num): + return state.api.users_build_read(user_token=state.user_token, set_num=set_num) @@ -343,23 +343,23 @@ def user_lost_parts(): @pass_state @click.argument('inv_part_id', type=int) @object_print -def user_lost_parts_create(ctx, inv_part_id): - return ctx.api.users_lost_parts_create(user_token=ctx.user_token, inv_part_id=inv_part_id) +def user_lost_parts_create(state, inv_part_id): + return state.api.users_lost_parts_create(user_token=state.user_token, inv_part_id=inv_part_id) @user_lost_parts.command('delete') @pass_state @click.argument('lost_part_id', type=int) @object_print -def user_lost_parts_delete(ctx, lost_part_id): - return ctx.api.users_lost_parts_delete(user_token=ctx.user_token, id=lost_part_id) +def user_lost_parts_delete(state, lost_part_id): + return state.api.users_lost_parts_delete(user_token=state.user_token, id=lost_part_id) @user_lost_parts.command('list') @pass_state @object_print -def user_lost_parts_list(ctx): - return ctx.api.users_lost_parts_list(user_token=ctx.user_token) +def user_lost_parts_list(state): + return state.api.users_lost_parts_list(user_token=state.user_token) @user.group('partlists') @@ -371,16 +371,16 @@ def user_partlists(): @pass_state @click.argument('name') @object_print -def user_partlists_create(ctx, name): - return ctx.api.users_partlists_create(user_token=ctx.user_token, +def user_partlists_create(state, name): + return state.api.users_partlists_create(user_token=state.user_token, name=name) @user_partlists.command('list') @pass_state @object_print -def user_partlists_list(ctx): - return ctx.api.users_partlists_list(user_token=ctx.user_token) +def user_partlists_list(state): + return state.api.users_partlists_list(user_token=state.user_token) def get_user_token(username='%%default%%'): diff --git a/cli/rebrickable_cli/cli/users.py b/cli/rebrickable_cli/cli/users.py index b3341bb..7eaebb7 100644 --- a/cli/rebrickable_cli/cli/users.py +++ b/cli/rebrickable_cli/cli/users.py @@ -11,30 +11,30 @@ @click.group(help='login a certain user or get global badges information') @pass_state -def users(ctx): - ctx.api = UsersApi(ctx.client) +def users(state): + state.api = UsersApi(state.client) @users.command(name='badges') @pass_state @object_print -def users_badges_list(ctx): - return ctx.api.users_badges_list() +def users_badges_list(state): + return state.api.users_badges_list() @add_typed_subcommands(Badge) @users.group('badge') @pass_state @get_or_push_context_obj(click.argument('id', type=int)) -def users_badge(ctx, id): - return ctx.api.users_badges_read(id=id) +def users_badge(state, id): + return state.api.users_badges_read(id=id) -def create_auth(ctx, username=None): +def create_auth(state, username=None): if username is None: username = input('Username: ') password = getpass() - return ctx.api.users_token_create(username, password) + return state.api.users_token_create(username, password) @users.command(name='login', help='login a certain user (store its user token)') @@ -44,9 +44,9 @@ def create_auth(ctx, username=None): is_flag=True, default=False) @click.argument('username', required=False) -def users_login(ctx, other, username=None): +def users_login(state, other, username=None): try: - users_token = create_auth(ctx, username) + users_token = create_auth(state, username) data = get_data() if not other: data.setdefault('users', {}).setdefault('%%default%%', {})['token'] = users_token diff --git a/cli/rebrickable_cli/utils.py b/cli/rebrickable_cli/utils.py index 56de0e5..8b67734 100644 --- a/cli/rebrickable_cli/utils.py +++ b/cli/rebrickable_cli/utils.py @@ -46,11 +46,11 @@ def __init__(self, enum, casesensitive=True): # TODO choices do not have the save order as enum super(EnumType, self).__init__(list(sorted(set(choices)))) - def convert(self, value, param, ctx): + def convert(self, value, param, state): if not self.__casesensitive: value = value.lower() - value = super(EnumType, self).convert(value, param, ctx) + value = super(EnumType, self).convert(value, param, state) if not self.__casesensitive: return next(_ for _ in self._EnumType__enum if _.name.lower() == diff --git a/tests/conftest.py b/tests/conftest.py index a951302..b815aa8 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -19,7 +19,7 @@ def fun(*args, **kwargs): @pytest.fixture def mocked_lego_api(): - with mock.patch('rebrickable_api.LegoApi', spec=LegoApi) as ctx_mock, \ + with mock.patch('rebrickable_api.LegoApi', spec=LegoApi) as state_mock, \ patch.object(LegoApi, 'lego_colors_read', side_effect=_read_echo(Color)), \ patch.object(LegoApi, 'lego_elements_read', side_effect=_read_echo(Element)), \ patch.object(LegoApi, 'lego_mocs_read', side_effect=_read_echo(Moc)), \ @@ -28,16 +28,16 @@ def mocked_lego_api(): patch.object(LegoApi, 'lego_parts_read', side_effect=_read_echo(Part)), \ patch.object(LegoApi, 'lego_sets_read', side_effect=_read_echo(Set)), \ patch.object(LegoApi, 'lego_themes_read', side_effect=_read_echo(Theme)): - yield ctx_mock + yield state_mock @pytest.fixture def mocked_users_api(): - with mock.patch('rebrickable_api.UsersApi', spec=UsersApi) as ctx_mock, \ + with mock.patch('rebrickable_api.UsersApi', spec=UsersApi) as state_mock, \ patch.object(UsersApi, 'users_badges_read', side_effect=_read_echo(Badge)), \ patch.object(UsersApi, 'users_build_read', side_effect=lambda *args, **kwargs: Build()), \ patch.object(UsersApi, 'users_partlists_parts_read', side_effect=_read_echo(PartListPart)), \ patch.object(UsersApi, 'users_partlists_read', side_effect=_read_echo(PartList)), \ patch.object(UsersApi, 'users_setlists_read', side_effect=_read_echo(SetList)), \ patch.object(UsersApi, 'users_sets_read', side_effect=_read_echo(Set)): - yield ctx_mock + yield state_mock diff --git a/tests/test_cli.py b/tests/test_cli.py index bd075df..b90460c 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -73,8 +73,8 @@ def test_main_command_pass_obj_invalid(runner): @user.command(name='test') @pass_state -def user_test(ctx): - assert ctx.user_token == 'user_token_value' +def user_test(state): + assert state.user_token == 'user_token_value' @mocked_data({'api_key': 'api_key_value', 'users': {'%%default%%': {'token': 'user_token_value'}}}) @@ -94,8 +94,8 @@ def test_users_command_pass_obj_invalid(runner): def test_lego_part_command_pass_obj(runner): @lego_part.command(name='test') @pass_state - def lego_part_test(ctx): - assert ctx.part_num == "3002" + def lego_part_test(state): + assert state.part_num == "3002" result = runner.invoke(main, ['lego', 'part', '3002', 'test']) assert result.exception is None @@ -107,9 +107,9 @@ def lego_part_test(ctx): def test_lego_part_color_command_pass_obj(runner): @lego_part_color.command(name='test') @pass_state - def lego_part_color_test(ctx): - assert ctx.color_id == 5 - assert ctx.part_num == "3002" + def lego_part_color_test(state): + assert state.color_id == 5 + assert state.part_num == "3002" result = runner.invoke(main, ['lego', 'part', '3002', 'color', '5', 'test']) assert result.exception is None @@ -120,8 +120,8 @@ def lego_part_color_test(ctx): def test_lego_color_command_pass_obj(runner): @lego_color.command(name='test') @pass_state - def lego_color_test(ctx): - assert ctx.color_id == 1234 + def lego_color_test(state): + assert state.color_id == 1234 result = runner.invoke(main, ['lego', 'color', '1234', 'test']) assert result.exception is None @@ -132,8 +132,8 @@ def lego_color_test(ctx): def test_lego_element_command_pass_obj(runner): @lego_element.command(name='test') @pass_state - def lego_element_test(ctx): - assert ctx.element_id == '1234' + def lego_element_test(state): + assert state.element_id == '1234' result = runner.invoke(main, ['lego', 'element', '1234', 'test']) assert result.exception is None @@ -144,8 +144,8 @@ def lego_element_test(ctx): def test_lego_moc_command_pass_obj(runner): @lego_moc.command(name='test') @pass_state - def lego_moc_test(ctx): - assert ctx.set_num == "MOC-1234" + def lego_moc_test(state): + assert state.set_num == "MOC-1234" result = runner.invoke(main, ['lego', 'moc', 'MOC-1234', 'test']) assert result.exception is None diff --git a/tests/test_models_integration.py b/tests/test_models_integration.py index 9dff1a0..48dd994 100644 --- a/tests/test_models_integration.py +++ b/tests/test_models_integration.py @@ -78,8 +78,8 @@ def test_users_badges_read_attributes(users_context): do_test(users_context.api.users_badges_read, dict(id=63), users_context) -def do_test(func, kwargs, ctx): - obj = ctx.client.sanitize_for_serialization(func(**kwargs)) +def do_test(func, kwargs, state): + obj = state.client.sanitize_for_serialization(func(**kwargs)) obj_no_preload = json.loads(func(_preload_content=False, **kwargs).data) # ignore Set last_modified_dt (datetime format) From e24208c2e975d8ba0b95f7d0b5e1b86a0aa15a69 Mon Sep 17 00:00:00 2001 From: rienafairefr Date: Tue, 11 Sep 2018 17:18:34 +0200 Subject: [PATCH 15/19] fix docs --- docs/cli.rst | 2 +- docs/conf.py | 16 ++--- docs/index.rst | 4 +- docs/reference/rebrickable_api/modules.rst | 8 +++ .../rebrickable_api.api.lego_api.rst | 7 +++ .../rebrickable_api/rebrickable_api.api.rst | 18 ++++++ .../rebrickable_api.api.users_api.rst | 7 +++ .../rebrickable_api.api_client.rst | 7 +++ .../rebrickable_api.configuration.rst | 7 +++ .../rebrickable_api.models.all_part.rst | 7 +++ ...rickable_api.models.array_of_all_parts.rst | 7 +++ ...rebrickable_api.models.array_of_badges.rst | 7 +++ ...rebrickable_api.models.array_of_colors.rst | 7 +++ ...brickable_api.models.array_of_elements.rst | 7 +++ ...le_api.models.array_of_inventory_parts.rst | 7 +++ ...ickable_api.models.array_of_lost_parts.rst | 7 +++ .../rebrickable_api.models.array_of_mocs.rst | 7 +++ ...le_api.models.array_of_part_categories.rst | 7 +++ ...i.models.array_of_part_colors_elements.rst | 7 +++ ..._api.models.array_of_part_colors_lists.rst | 7 +++ ...le_api.models.array_of_part_list_parts.rst | 7 +++ ...ickable_api.models.array_of_part_lists.rst | 7 +++ .../rebrickable_api.models.array_of_parts.rst | 7 +++ ...able_api.models.array_of_set_list_sets.rst | 7 +++ ...rickable_api.models.array_of_set_lists.rst | 7 +++ .../rebrickable_api.models.array_of_sets.rst | 7 +++ ...rebrickable_api.models.array_of_themes.rst | 7 +++ .../rebrickable_api.models.badge.rst | 7 +++ .../rebrickable_api.models.build.rst | 7 +++ .../rebrickable_api.models.build_options.rst | 7 +++ .../rebrickable_api.models.color.rst | 7 +++ .../rebrickable_api.models.element.rst | 7 +++ .../rebrickable_api.models.error_message.rst | 7 +++ ...brickable_api.models.external_color_id.rst | 7 +++ ...rickable_api.models.external_color_ids.rst | 7 +++ .../rebrickable_api.models.external_ids.rst | 7 +++ .../rebrickable_api.models.inventory_part.rst | 7 +++ .../rebrickable_api.models.lego.rst | 7 +++ .../rebrickable_api.models.lost_part.rst | 7 +++ .../rebrickable_api.models.moc.rst | 7 +++ .../rebrickable_api.models.part.rst | 7 +++ .../rebrickable_api.models.part_category.rst | 7 +++ ...ickable_api.models.part_colors_element.rst | 7 +++ ...ebrickable_api.models.part_colors_list.rst | 7 +++ .../rebrickable_api.models.part_list.rst | 7 +++ .../rebrickable_api.models.part_list_part.rst | 7 +++ .../rebrickable_api.models.profile.rst | 7 +++ .../rebrickable_api.models.rewards.rst | 7 +++ .../rebrickable_api.models.rst | 60 ++++++++++++++++++ .../rebrickable_api.models.set.rst | 7 +++ .../rebrickable_api.models.set_list.rst | 7 +++ .../rebrickable_api.models.set_list_set.rst | 7 +++ .../rebrickable_api.models.theme.rst | 7 +++ ...ckable_api.models.users_token_response.rst | 7 +++ .../rebrickable_api/rebrickable_api.rest.rst | 7 +++ .../rebrickable_api/rebrickable_api.rst | 27 ++++++++ docs/reference/rebrickable_api/test.rst | 62 +++++++++++++++++++ .../rebrickable_api/test.test_all_part.rst | 7 +++ .../test.test_array_of_all_parts.rst | 7 +++ .../test.test_array_of_badges.rst | 7 +++ .../test.test_array_of_colors.rst | 7 +++ .../test.test_array_of_elements.rst | 7 +++ .../test.test_array_of_inventory_parts.rst | 7 +++ .../test.test_array_of_lost_parts.rst | 7 +++ .../test.test_array_of_mocs.rst | 7 +++ .../test.test_array_of_part_categories.rst | 7 +++ ...est.test_array_of_part_colors_elements.rst | 7 +++ .../test.test_array_of_part_colors_lists.rst | 7 +++ .../test.test_array_of_part_list_parts.rst | 7 +++ .../test.test_array_of_part_lists.rst | 7 +++ .../test.test_array_of_parts.rst | 7 +++ .../test.test_array_of_set_list_sets.rst | 7 +++ .../test.test_array_of_set_lists.rst | 7 +++ .../test.test_array_of_sets.rst | 7 +++ .../test.test_array_of_themes.rst | 7 +++ .../rebrickable_api/test.test_badge.rst | 7 +++ .../rebrickable_api/test.test_build.rst | 7 +++ .../test.test_build_options.rst | 7 +++ .../rebrickable_api/test.test_color.rst | 7 +++ .../rebrickable_api/test.test_element.rst | 7 +++ .../test.test_error_message.rst | 7 +++ .../test.test_external_color_id.rst | 7 +++ .../test.test_external_color_ids.rst | 7 +++ .../test.test_external_ids.rst | 7 +++ .../test.test_inventory_part.rst | 7 +++ .../rebrickable_api/test.test_lego.rst | 7 +++ .../rebrickable_api/test.test_lego_api.rst | 7 +++ .../rebrickable_api/test.test_lost_part.rst | 7 +++ .../rebrickable_api/test.test_moc.rst | 7 +++ .../rebrickable_api/test.test_part.rst | 7 +++ .../test.test_part_category.rst | 7 +++ .../test.test_part_colors_element.rst | 7 +++ .../test.test_part_colors_list.rst | 7 +++ .../rebrickable_api/test.test_part_list.rst | 7 +++ .../test.test_part_list_part.rst | 7 +++ .../rebrickable_api/test.test_profile.rst | 7 +++ .../rebrickable_api/test.test_rewards.rst | 7 +++ .../rebrickable_api/test.test_set.rst | 7 +++ .../rebrickable_api/test.test_set_list.rst | 7 +++ .../test.test_set_list_set.rst | 7 +++ .../rebrickable_api/test.test_theme.rst | 7 +++ .../rebrickable_api/test.test_users_api.rst | 7 +++ .../test.test_users_token_response.rst | 7 +++ .../cli.rebrickable_cli.cli.common.rst | 7 +++ .../cli.rebrickable_cli.cli.lego.rst | 7 +++ .../cli.rebrickable_cli.cli.main.rst | 7 +++ .../cli.rebrickable_cli.cli.rst | 21 +++++++ .../cli.rebrickable_cli.cli.user.rst | 7 +++ .../cli.rebrickable_cli.cli.users.rst | 7 +++ .../rebrickable_cli/cli.rebrickable_cli.rst | 24 +++++++ .../cli.rebrickable_cli.utils.rst | 7 +++ docs/reference/rebrickable_cli/cli.rst | 17 +++++ docs/reference/rebrickable_cli/modules.rst | 7 +++ 113 files changed, 962 insertions(+), 11 deletions(-) create mode 100644 docs/reference/rebrickable_api/modules.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.api.lego_api.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.api.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.api.users_api.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.api_client.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.configuration.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.all_part.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.array_of_all_parts.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.array_of_badges.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.array_of_colors.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.array_of_elements.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.array_of_inventory_parts.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.array_of_lost_parts.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.array_of_mocs.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.array_of_part_categories.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.array_of_part_colors_elements.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.array_of_part_colors_lists.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.array_of_part_list_parts.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.array_of_part_lists.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.array_of_parts.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.array_of_set_list_sets.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.array_of_set_lists.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.array_of_sets.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.array_of_themes.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.badge.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.build.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.build_options.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.color.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.element.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.error_message.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.external_color_id.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.external_color_ids.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.external_ids.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.inventory_part.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.lego.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.lost_part.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.moc.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.part.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.part_category.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.part_colors_element.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.part_colors_list.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.part_list.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.part_list_part.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.profile.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.rewards.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.set.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.set_list.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.set_list_set.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.theme.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.models.users_token_response.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.rest.rst create mode 100644 docs/reference/rebrickable_api/rebrickable_api.rst create mode 100644 docs/reference/rebrickable_api/test.rst create mode 100644 docs/reference/rebrickable_api/test.test_all_part.rst create mode 100644 docs/reference/rebrickable_api/test.test_array_of_all_parts.rst create mode 100644 docs/reference/rebrickable_api/test.test_array_of_badges.rst create mode 100644 docs/reference/rebrickable_api/test.test_array_of_colors.rst create mode 100644 docs/reference/rebrickable_api/test.test_array_of_elements.rst create mode 100644 docs/reference/rebrickable_api/test.test_array_of_inventory_parts.rst create mode 100644 docs/reference/rebrickable_api/test.test_array_of_lost_parts.rst create mode 100644 docs/reference/rebrickable_api/test.test_array_of_mocs.rst create mode 100644 docs/reference/rebrickable_api/test.test_array_of_part_categories.rst create mode 100644 docs/reference/rebrickable_api/test.test_array_of_part_colors_elements.rst create mode 100644 docs/reference/rebrickable_api/test.test_array_of_part_colors_lists.rst create mode 100644 docs/reference/rebrickable_api/test.test_array_of_part_list_parts.rst create mode 100644 docs/reference/rebrickable_api/test.test_array_of_part_lists.rst create mode 100644 docs/reference/rebrickable_api/test.test_array_of_parts.rst create mode 100644 docs/reference/rebrickable_api/test.test_array_of_set_list_sets.rst create mode 100644 docs/reference/rebrickable_api/test.test_array_of_set_lists.rst create mode 100644 docs/reference/rebrickable_api/test.test_array_of_sets.rst create mode 100644 docs/reference/rebrickable_api/test.test_array_of_themes.rst create mode 100644 docs/reference/rebrickable_api/test.test_badge.rst create mode 100644 docs/reference/rebrickable_api/test.test_build.rst create mode 100644 docs/reference/rebrickable_api/test.test_build_options.rst create mode 100644 docs/reference/rebrickable_api/test.test_color.rst create mode 100644 docs/reference/rebrickable_api/test.test_element.rst create mode 100644 docs/reference/rebrickable_api/test.test_error_message.rst create mode 100644 docs/reference/rebrickable_api/test.test_external_color_id.rst create mode 100644 docs/reference/rebrickable_api/test.test_external_color_ids.rst create mode 100644 docs/reference/rebrickable_api/test.test_external_ids.rst create mode 100644 docs/reference/rebrickable_api/test.test_inventory_part.rst create mode 100644 docs/reference/rebrickable_api/test.test_lego.rst create mode 100644 docs/reference/rebrickable_api/test.test_lego_api.rst create mode 100644 docs/reference/rebrickable_api/test.test_lost_part.rst create mode 100644 docs/reference/rebrickable_api/test.test_moc.rst create mode 100644 docs/reference/rebrickable_api/test.test_part.rst create mode 100644 docs/reference/rebrickable_api/test.test_part_category.rst create mode 100644 docs/reference/rebrickable_api/test.test_part_colors_element.rst create mode 100644 docs/reference/rebrickable_api/test.test_part_colors_list.rst create mode 100644 docs/reference/rebrickable_api/test.test_part_list.rst create mode 100644 docs/reference/rebrickable_api/test.test_part_list_part.rst create mode 100644 docs/reference/rebrickable_api/test.test_profile.rst create mode 100644 docs/reference/rebrickable_api/test.test_rewards.rst create mode 100644 docs/reference/rebrickable_api/test.test_set.rst create mode 100644 docs/reference/rebrickable_api/test.test_set_list.rst create mode 100644 docs/reference/rebrickable_api/test.test_set_list_set.rst create mode 100644 docs/reference/rebrickable_api/test.test_theme.rst create mode 100644 docs/reference/rebrickable_api/test.test_users_api.rst create mode 100644 docs/reference/rebrickable_api/test.test_users_token_response.rst create mode 100644 docs/reference/rebrickable_cli/cli.rebrickable_cli.cli.common.rst create mode 100644 docs/reference/rebrickable_cli/cli.rebrickable_cli.cli.lego.rst create mode 100644 docs/reference/rebrickable_cli/cli.rebrickable_cli.cli.main.rst create mode 100644 docs/reference/rebrickable_cli/cli.rebrickable_cli.cli.rst create mode 100644 docs/reference/rebrickable_cli/cli.rebrickable_cli.cli.user.rst create mode 100644 docs/reference/rebrickable_cli/cli.rebrickable_cli.cli.users.rst create mode 100644 docs/reference/rebrickable_cli/cli.rebrickable_cli.rst create mode 100644 docs/reference/rebrickable_cli/cli.rebrickable_cli.utils.rst create mode 100644 docs/reference/rebrickable_cli/cli.rst create mode 100644 docs/reference/rebrickable_cli/modules.rst diff --git a/docs/cli.rst b/docs/cli.rst index af1a711..c1c32f8 100644 --- a/docs/cli.rst +++ b/docs/cli.rst @@ -1,7 +1,7 @@ CLI documentation ================= -.. click:: rebrickable_cli.cli:main +.. click:: rebrickable_cli.cli.main:main :prog: rebrickable :show-nested: diff --git a/docs/conf.py b/docs/conf.py index 4e1325a..66013ed 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -16,9 +16,9 @@ # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # -#import os -#import sys -#sys.path.insert(0, os.path.abspath('.')) +# import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) # -- General configuration ------------------------------------------------ @@ -96,7 +96,7 @@ # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". -#html_static_path = ['_static'] +# html_static_path = ['_static'] # Custom sidebar templates, must be a dictionary that maps document names # to template names. @@ -171,19 +171,19 @@ def run_apidoc(_): sys.path.append(os.path.join(os.path.dirname(__file__), '..')) cur_dir = os.path.abspath(os.path.dirname(__file__)) modules = [ - ('api','api'), - ('cli','cli') + ('api', 'rebrickable_api'), + ('cli', 'rebrickable_cli') ] def rel(pth): return os.path.abspath(os.path.join(cur_dir, "..", pth)) - excludes = ['../**setup.py'] + excludes = ['test', '../**setup.py'] for module, dir_module in modules: output_dir = rel(os.path.join('docs', 'reference', dir_module)) cmd = ['--force', '--separate', '-o', output_dir, rel(module)] + excludes - print('Calling sphinx-apidoc: ['+ ' '.join(cmd) + ']') + print('Calling sphinx-apidoc: [' + ' '.join(cmd) + ']') main(cmd) diff --git a/docs/index.rst b/docs/index.rst index 49b8783..b84b568 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -12,8 +12,8 @@ Welcome to pyrebrickable's documentation! CLI API - CLI Reference - Auto-generated API Client Reference + CLI Reference + Auto-generated API Client Reference Database diff --git a/docs/reference/rebrickable_api/modules.rst b/docs/reference/rebrickable_api/modules.rst new file mode 100644 index 0000000..d40576e --- /dev/null +++ b/docs/reference/rebrickable_api/modules.rst @@ -0,0 +1,8 @@ +api +=== + +.. toctree:: + :maxdepth: 4 + + rebrickable_api + test diff --git a/docs/reference/rebrickable_api/rebrickable_api.api.lego_api.rst b/docs/reference/rebrickable_api/rebrickable_api.api.lego_api.rst new file mode 100644 index 0000000..0f4acdb --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.api.lego_api.rst @@ -0,0 +1,7 @@ +rebrickable\_api.api.lego\_api module +===================================== + +.. automodule:: rebrickable_api.api.lego_api + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.api.rst b/docs/reference/rebrickable_api/rebrickable_api.api.rst new file mode 100644 index 0000000..824c364 --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.api.rst @@ -0,0 +1,18 @@ +rebrickable\_api.api package +============================ + +Submodules +---------- + +.. toctree:: + + rebrickable_api.api.lego_api + rebrickable_api.api.users_api + +Module contents +--------------- + +.. automodule:: rebrickable_api.api + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.api.users_api.rst b/docs/reference/rebrickable_api/rebrickable_api.api.users_api.rst new file mode 100644 index 0000000..0c3197a --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.api.users_api.rst @@ -0,0 +1,7 @@ +rebrickable\_api.api.users\_api module +====================================== + +.. automodule:: rebrickable_api.api.users_api + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.api_client.rst b/docs/reference/rebrickable_api/rebrickable_api.api_client.rst new file mode 100644 index 0000000..1bc6d70 --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.api_client.rst @@ -0,0 +1,7 @@ +rebrickable\_api.api\_client module +=================================== + +.. automodule:: rebrickable_api.api_client + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.configuration.rst b/docs/reference/rebrickable_api/rebrickable_api.configuration.rst new file mode 100644 index 0000000..88e32c8 --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.configuration.rst @@ -0,0 +1,7 @@ +rebrickable\_api.configuration module +===================================== + +.. automodule:: rebrickable_api.configuration + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.all_part.rst b/docs/reference/rebrickable_api/rebrickable_api.models.all_part.rst new file mode 100644 index 0000000..144a342 --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.all_part.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.all\_part module +======================================== + +.. automodule:: rebrickable_api.models.all_part + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.array_of_all_parts.rst b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_all_parts.rst new file mode 100644 index 0000000..20769bc --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_all_parts.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.array\_of\_all\_parts module +==================================================== + +.. automodule:: rebrickable_api.models.array_of_all_parts + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.array_of_badges.rst b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_badges.rst new file mode 100644 index 0000000..c98dc5c --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_badges.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.array\_of\_badges module +================================================ + +.. automodule:: rebrickable_api.models.array_of_badges + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.array_of_colors.rst b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_colors.rst new file mode 100644 index 0000000..2db4912 --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_colors.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.array\_of\_colors module +================================================ + +.. automodule:: rebrickable_api.models.array_of_colors + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.array_of_elements.rst b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_elements.rst new file mode 100644 index 0000000..f93fb95 --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_elements.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.array\_of\_elements module +================================================== + +.. automodule:: rebrickable_api.models.array_of_elements + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.array_of_inventory_parts.rst b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_inventory_parts.rst new file mode 100644 index 0000000..396acd6 --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_inventory_parts.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.array\_of\_inventory\_parts module +========================================================== + +.. automodule:: rebrickable_api.models.array_of_inventory_parts + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.array_of_lost_parts.rst b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_lost_parts.rst new file mode 100644 index 0000000..74a0b4c --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_lost_parts.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.array\_of\_lost\_parts module +===================================================== + +.. automodule:: rebrickable_api.models.array_of_lost_parts + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.array_of_mocs.rst b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_mocs.rst new file mode 100644 index 0000000..3ba0b43 --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_mocs.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.array\_of\_mocs module +============================================== + +.. automodule:: rebrickable_api.models.array_of_mocs + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.array_of_part_categories.rst b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_part_categories.rst new file mode 100644 index 0000000..0f727b1 --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_part_categories.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.array\_of\_part\_categories module +========================================================== + +.. automodule:: rebrickable_api.models.array_of_part_categories + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.array_of_part_colors_elements.rst b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_part_colors_elements.rst new file mode 100644 index 0000000..dab29b5 --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_part_colors_elements.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.array\_of\_part\_colors\_elements module +================================================================ + +.. automodule:: rebrickable_api.models.array_of_part_colors_elements + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.array_of_part_colors_lists.rst b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_part_colors_lists.rst new file mode 100644 index 0000000..c85b7ec --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_part_colors_lists.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.array\_of\_part\_colors\_lists module +============================================================= + +.. automodule:: rebrickable_api.models.array_of_part_colors_lists + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.array_of_part_list_parts.rst b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_part_list_parts.rst new file mode 100644 index 0000000..2376747 --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_part_list_parts.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.array\_of\_part\_list\_parts module +=========================================================== + +.. automodule:: rebrickable_api.models.array_of_part_list_parts + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.array_of_part_lists.rst b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_part_lists.rst new file mode 100644 index 0000000..4abf42b --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_part_lists.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.array\_of\_part\_lists module +===================================================== + +.. automodule:: rebrickable_api.models.array_of_part_lists + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.array_of_parts.rst b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_parts.rst new file mode 100644 index 0000000..34e3dd1 --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_parts.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.array\_of\_parts module +=============================================== + +.. automodule:: rebrickable_api.models.array_of_parts + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.array_of_set_list_sets.rst b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_set_list_sets.rst new file mode 100644 index 0000000..978b0da --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_set_list_sets.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.array\_of\_set\_list\_sets module +========================================================= + +.. automodule:: rebrickable_api.models.array_of_set_list_sets + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.array_of_set_lists.rst b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_set_lists.rst new file mode 100644 index 0000000..52e5a1c --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_set_lists.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.array\_of\_set\_lists module +==================================================== + +.. automodule:: rebrickable_api.models.array_of_set_lists + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.array_of_sets.rst b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_sets.rst new file mode 100644 index 0000000..d3acd50 --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_sets.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.array\_of\_sets module +============================================== + +.. automodule:: rebrickable_api.models.array_of_sets + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.array_of_themes.rst b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_themes.rst new file mode 100644 index 0000000..92a15ad --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.array_of_themes.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.array\_of\_themes module +================================================ + +.. automodule:: rebrickable_api.models.array_of_themes + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.badge.rst b/docs/reference/rebrickable_api/rebrickable_api.models.badge.rst new file mode 100644 index 0000000..47831a0 --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.badge.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.badge module +==================================== + +.. automodule:: rebrickable_api.models.badge + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.build.rst b/docs/reference/rebrickable_api/rebrickable_api.models.build.rst new file mode 100644 index 0000000..3692cb3 --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.build.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.build module +==================================== + +.. automodule:: rebrickable_api.models.build + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.build_options.rst b/docs/reference/rebrickable_api/rebrickable_api.models.build_options.rst new file mode 100644 index 0000000..5e7447c --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.build_options.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.build\_options module +============================================= + +.. automodule:: rebrickable_api.models.build_options + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.color.rst b/docs/reference/rebrickable_api/rebrickable_api.models.color.rst new file mode 100644 index 0000000..3d8465b --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.color.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.color module +==================================== + +.. automodule:: rebrickable_api.models.color + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.element.rst b/docs/reference/rebrickable_api/rebrickable_api.models.element.rst new file mode 100644 index 0000000..4f604ac --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.element.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.element module +====================================== + +.. automodule:: rebrickable_api.models.element + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.error_message.rst b/docs/reference/rebrickable_api/rebrickable_api.models.error_message.rst new file mode 100644 index 0000000..bc6522c --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.error_message.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.error\_message module +============================================= + +.. automodule:: rebrickable_api.models.error_message + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.external_color_id.rst b/docs/reference/rebrickable_api/rebrickable_api.models.external_color_id.rst new file mode 100644 index 0000000..cb1a21c --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.external_color_id.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.external\_color\_id module +================================================== + +.. automodule:: rebrickable_api.models.external_color_id + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.external_color_ids.rst b/docs/reference/rebrickable_api/rebrickable_api.models.external_color_ids.rst new file mode 100644 index 0000000..a15d396 --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.external_color_ids.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.external\_color\_ids module +=================================================== + +.. automodule:: rebrickable_api.models.external_color_ids + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.external_ids.rst b/docs/reference/rebrickable_api/rebrickable_api.models.external_ids.rst new file mode 100644 index 0000000..f20e008 --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.external_ids.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.external\_ids module +============================================ + +.. automodule:: rebrickable_api.models.external_ids + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.inventory_part.rst b/docs/reference/rebrickable_api/rebrickable_api.models.inventory_part.rst new file mode 100644 index 0000000..815e188 --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.inventory_part.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.inventory\_part module +============================================== + +.. automodule:: rebrickable_api.models.inventory_part + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.lego.rst b/docs/reference/rebrickable_api/rebrickable_api.models.lego.rst new file mode 100644 index 0000000..f0d3b42 --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.lego.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.lego module +=================================== + +.. automodule:: rebrickable_api.models.lego + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.lost_part.rst b/docs/reference/rebrickable_api/rebrickable_api.models.lost_part.rst new file mode 100644 index 0000000..06e77f8 --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.lost_part.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.lost\_part module +========================================= + +.. automodule:: rebrickable_api.models.lost_part + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.moc.rst b/docs/reference/rebrickable_api/rebrickable_api.models.moc.rst new file mode 100644 index 0000000..22e0b48 --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.moc.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.moc module +================================== + +.. automodule:: rebrickable_api.models.moc + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.part.rst b/docs/reference/rebrickable_api/rebrickable_api.models.part.rst new file mode 100644 index 0000000..65a872c --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.part.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.part module +=================================== + +.. automodule:: rebrickable_api.models.part + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.part_category.rst b/docs/reference/rebrickable_api/rebrickable_api.models.part_category.rst new file mode 100644 index 0000000..2f35fc3 --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.part_category.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.part\_category module +============================================= + +.. automodule:: rebrickable_api.models.part_category + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.part_colors_element.rst b/docs/reference/rebrickable_api/rebrickable_api.models.part_colors_element.rst new file mode 100644 index 0000000..61a3a6b --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.part_colors_element.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.part\_colors\_element module +==================================================== + +.. automodule:: rebrickable_api.models.part_colors_element + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.part_colors_list.rst b/docs/reference/rebrickable_api/rebrickable_api.models.part_colors_list.rst new file mode 100644 index 0000000..0c2f6b0 --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.part_colors_list.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.part\_colors\_list module +================================================= + +.. automodule:: rebrickable_api.models.part_colors_list + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.part_list.rst b/docs/reference/rebrickable_api/rebrickable_api.models.part_list.rst new file mode 100644 index 0000000..a71a793 --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.part_list.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.part\_list module +========================================= + +.. automodule:: rebrickable_api.models.part_list + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.part_list_part.rst b/docs/reference/rebrickable_api/rebrickable_api.models.part_list_part.rst new file mode 100644 index 0000000..78867d2 --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.part_list_part.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.part\_list\_part module +=============================================== + +.. automodule:: rebrickable_api.models.part_list_part + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.profile.rst b/docs/reference/rebrickable_api/rebrickable_api.models.profile.rst new file mode 100644 index 0000000..e525427 --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.profile.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.profile module +====================================== + +.. automodule:: rebrickable_api.models.profile + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.rewards.rst b/docs/reference/rebrickable_api/rebrickable_api.models.rewards.rst new file mode 100644 index 0000000..b2441d5 --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.rewards.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.rewards module +====================================== + +.. automodule:: rebrickable_api.models.rewards + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.rst b/docs/reference/rebrickable_api/rebrickable_api.models.rst new file mode 100644 index 0000000..d84869a --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.rst @@ -0,0 +1,60 @@ +rebrickable\_api.models package +=============================== + +Submodules +---------- + +.. toctree:: + + rebrickable_api.models.all_part + rebrickable_api.models.array_of_all_parts + rebrickable_api.models.array_of_badges + rebrickable_api.models.array_of_colors + rebrickable_api.models.array_of_elements + rebrickable_api.models.array_of_inventory_parts + rebrickable_api.models.array_of_lost_parts + rebrickable_api.models.array_of_mocs + rebrickable_api.models.array_of_part_categories + rebrickable_api.models.array_of_part_colors_elements + rebrickable_api.models.array_of_part_colors_lists + rebrickable_api.models.array_of_part_list_parts + rebrickable_api.models.array_of_part_lists + rebrickable_api.models.array_of_parts + rebrickable_api.models.array_of_set_list_sets + rebrickable_api.models.array_of_set_lists + rebrickable_api.models.array_of_sets + rebrickable_api.models.array_of_themes + rebrickable_api.models.badge + rebrickable_api.models.build + rebrickable_api.models.build_options + rebrickable_api.models.color + rebrickable_api.models.element + rebrickable_api.models.error_message + rebrickable_api.models.external_color_id + rebrickable_api.models.external_color_ids + rebrickable_api.models.external_ids + rebrickable_api.models.inventory_part + rebrickable_api.models.lego + rebrickable_api.models.lost_part + rebrickable_api.models.moc + rebrickable_api.models.part + rebrickable_api.models.part_category + rebrickable_api.models.part_colors_element + rebrickable_api.models.part_colors_list + rebrickable_api.models.part_list + rebrickable_api.models.part_list_part + rebrickable_api.models.profile + rebrickable_api.models.rewards + rebrickable_api.models.set + rebrickable_api.models.set_list + rebrickable_api.models.set_list_set + rebrickable_api.models.theme + rebrickable_api.models.users_token_response + +Module contents +--------------- + +.. automodule:: rebrickable_api.models + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.set.rst b/docs/reference/rebrickable_api/rebrickable_api.models.set.rst new file mode 100644 index 0000000..c8e456d --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.set.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.set module +================================== + +.. automodule:: rebrickable_api.models.set + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.set_list.rst b/docs/reference/rebrickable_api/rebrickable_api.models.set_list.rst new file mode 100644 index 0000000..31844bc --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.set_list.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.set\_list module +======================================== + +.. automodule:: rebrickable_api.models.set_list + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.set_list_set.rst b/docs/reference/rebrickable_api/rebrickable_api.models.set_list_set.rst new file mode 100644 index 0000000..6379483 --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.set_list_set.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.set\_list\_set module +============================================= + +.. automodule:: rebrickable_api.models.set_list_set + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.theme.rst b/docs/reference/rebrickable_api/rebrickable_api.models.theme.rst new file mode 100644 index 0000000..70e4fa3 --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.theme.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.theme module +==================================== + +.. automodule:: rebrickable_api.models.theme + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.models.users_token_response.rst b/docs/reference/rebrickable_api/rebrickable_api.models.users_token_response.rst new file mode 100644 index 0000000..df52934 --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.models.users_token_response.rst @@ -0,0 +1,7 @@ +rebrickable\_api.models.users\_token\_response module +===================================================== + +.. automodule:: rebrickable_api.models.users_token_response + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.rest.rst b/docs/reference/rebrickable_api/rebrickable_api.rest.rst new file mode 100644 index 0000000..0cfd07d --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.rest.rst @@ -0,0 +1,7 @@ +rebrickable\_api.rest module +============================ + +.. automodule:: rebrickable_api.rest + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/rebrickable_api.rst b/docs/reference/rebrickable_api/rebrickable_api.rst new file mode 100644 index 0000000..45afeaf --- /dev/null +++ b/docs/reference/rebrickable_api/rebrickable_api.rst @@ -0,0 +1,27 @@ +rebrickable\_api package +======================== + +Subpackages +----------- + +.. toctree:: + + rebrickable_api.api + rebrickable_api.models + +Submodules +---------- + +.. toctree:: + + rebrickable_api.api_client + rebrickable_api.configuration + rebrickable_api.rest + +Module contents +--------------- + +.. automodule:: rebrickable_api + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.rst b/docs/reference/rebrickable_api/test.rst new file mode 100644 index 0000000..e8cf436 --- /dev/null +++ b/docs/reference/rebrickable_api/test.rst @@ -0,0 +1,62 @@ +test package +============ + +Submodules +---------- + +.. toctree:: + + test.test_all_part + test.test_array_of_all_parts + test.test_array_of_badges + test.test_array_of_colors + test.test_array_of_elements + test.test_array_of_inventory_parts + test.test_array_of_lost_parts + test.test_array_of_mocs + test.test_array_of_part_categories + test.test_array_of_part_colors_elements + test.test_array_of_part_colors_lists + test.test_array_of_part_list_parts + test.test_array_of_part_lists + test.test_array_of_parts + test.test_array_of_set_list_sets + test.test_array_of_set_lists + test.test_array_of_sets + test.test_array_of_themes + test.test_badge + test.test_build + test.test_build_options + test.test_color + test.test_element + test.test_error_message + test.test_external_color_id + test.test_external_color_ids + test.test_external_ids + test.test_inventory_part + test.test_lego + test.test_lego_api + test.test_lost_part + test.test_moc + test.test_part + test.test_part_category + test.test_part_colors_element + test.test_part_colors_list + test.test_part_list + test.test_part_list_part + test.test_profile + test.test_rewards + test.test_set + test.test_set_list + test.test_set_list_set + test.test_theme + test.test_users_api + test.test_users_token_response + +Module contents +--------------- + +.. automodule:: test + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_all_part.rst b/docs/reference/rebrickable_api/test.test_all_part.rst new file mode 100644 index 0000000..f63b5df --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_all_part.rst @@ -0,0 +1,7 @@ +test.test\_all\_part module +=========================== + +.. automodule:: test.test_all_part + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_array_of_all_parts.rst b/docs/reference/rebrickable_api/test.test_array_of_all_parts.rst new file mode 100644 index 0000000..ce19673 --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_array_of_all_parts.rst @@ -0,0 +1,7 @@ +test.test\_array\_of\_all\_parts module +======================================= + +.. automodule:: test.test_array_of_all_parts + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_array_of_badges.rst b/docs/reference/rebrickable_api/test.test_array_of_badges.rst new file mode 100644 index 0000000..2302efe --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_array_of_badges.rst @@ -0,0 +1,7 @@ +test.test\_array\_of\_badges module +=================================== + +.. automodule:: test.test_array_of_badges + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_array_of_colors.rst b/docs/reference/rebrickable_api/test.test_array_of_colors.rst new file mode 100644 index 0000000..0ab8167 --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_array_of_colors.rst @@ -0,0 +1,7 @@ +test.test\_array\_of\_colors module +=================================== + +.. automodule:: test.test_array_of_colors + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_array_of_elements.rst b/docs/reference/rebrickable_api/test.test_array_of_elements.rst new file mode 100644 index 0000000..6f5f20b --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_array_of_elements.rst @@ -0,0 +1,7 @@ +test.test\_array\_of\_elements module +===================================== + +.. automodule:: test.test_array_of_elements + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_array_of_inventory_parts.rst b/docs/reference/rebrickable_api/test.test_array_of_inventory_parts.rst new file mode 100644 index 0000000..013b13c --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_array_of_inventory_parts.rst @@ -0,0 +1,7 @@ +test.test\_array\_of\_inventory\_parts module +============================================= + +.. automodule:: test.test_array_of_inventory_parts + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_array_of_lost_parts.rst b/docs/reference/rebrickable_api/test.test_array_of_lost_parts.rst new file mode 100644 index 0000000..d90f362 --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_array_of_lost_parts.rst @@ -0,0 +1,7 @@ +test.test\_array\_of\_lost\_parts module +======================================== + +.. automodule:: test.test_array_of_lost_parts + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_array_of_mocs.rst b/docs/reference/rebrickable_api/test.test_array_of_mocs.rst new file mode 100644 index 0000000..be38cf0 --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_array_of_mocs.rst @@ -0,0 +1,7 @@ +test.test\_array\_of\_mocs module +================================= + +.. automodule:: test.test_array_of_mocs + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_array_of_part_categories.rst b/docs/reference/rebrickable_api/test.test_array_of_part_categories.rst new file mode 100644 index 0000000..d561fe0 --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_array_of_part_categories.rst @@ -0,0 +1,7 @@ +test.test\_array\_of\_part\_categories module +============================================= + +.. automodule:: test.test_array_of_part_categories + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_array_of_part_colors_elements.rst b/docs/reference/rebrickable_api/test.test_array_of_part_colors_elements.rst new file mode 100644 index 0000000..81af6fb --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_array_of_part_colors_elements.rst @@ -0,0 +1,7 @@ +test.test\_array\_of\_part\_colors\_elements module +=================================================== + +.. automodule:: test.test_array_of_part_colors_elements + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_array_of_part_colors_lists.rst b/docs/reference/rebrickable_api/test.test_array_of_part_colors_lists.rst new file mode 100644 index 0000000..44449aa --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_array_of_part_colors_lists.rst @@ -0,0 +1,7 @@ +test.test\_array\_of\_part\_colors\_lists module +================================================ + +.. automodule:: test.test_array_of_part_colors_lists + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_array_of_part_list_parts.rst b/docs/reference/rebrickable_api/test.test_array_of_part_list_parts.rst new file mode 100644 index 0000000..aea982e --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_array_of_part_list_parts.rst @@ -0,0 +1,7 @@ +test.test\_array\_of\_part\_list\_parts module +============================================== + +.. automodule:: test.test_array_of_part_list_parts + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_array_of_part_lists.rst b/docs/reference/rebrickable_api/test.test_array_of_part_lists.rst new file mode 100644 index 0000000..093810c --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_array_of_part_lists.rst @@ -0,0 +1,7 @@ +test.test\_array\_of\_part\_lists module +======================================== + +.. automodule:: test.test_array_of_part_lists + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_array_of_parts.rst b/docs/reference/rebrickable_api/test.test_array_of_parts.rst new file mode 100644 index 0000000..046b086 --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_array_of_parts.rst @@ -0,0 +1,7 @@ +test.test\_array\_of\_parts module +================================== + +.. automodule:: test.test_array_of_parts + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_array_of_set_list_sets.rst b/docs/reference/rebrickable_api/test.test_array_of_set_list_sets.rst new file mode 100644 index 0000000..6298b76 --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_array_of_set_list_sets.rst @@ -0,0 +1,7 @@ +test.test\_array\_of\_set\_list\_sets module +============================================ + +.. automodule:: test.test_array_of_set_list_sets + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_array_of_set_lists.rst b/docs/reference/rebrickable_api/test.test_array_of_set_lists.rst new file mode 100644 index 0000000..c436513 --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_array_of_set_lists.rst @@ -0,0 +1,7 @@ +test.test\_array\_of\_set\_lists module +======================================= + +.. automodule:: test.test_array_of_set_lists + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_array_of_sets.rst b/docs/reference/rebrickable_api/test.test_array_of_sets.rst new file mode 100644 index 0000000..3db2575 --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_array_of_sets.rst @@ -0,0 +1,7 @@ +test.test\_array\_of\_sets module +================================= + +.. automodule:: test.test_array_of_sets + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_array_of_themes.rst b/docs/reference/rebrickable_api/test.test_array_of_themes.rst new file mode 100644 index 0000000..5b9f0a5 --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_array_of_themes.rst @@ -0,0 +1,7 @@ +test.test\_array\_of\_themes module +=================================== + +.. automodule:: test.test_array_of_themes + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_badge.rst b/docs/reference/rebrickable_api/test.test_badge.rst new file mode 100644 index 0000000..f801f82 --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_badge.rst @@ -0,0 +1,7 @@ +test.test\_badge module +======================= + +.. automodule:: test.test_badge + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_build.rst b/docs/reference/rebrickable_api/test.test_build.rst new file mode 100644 index 0000000..9f12865 --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_build.rst @@ -0,0 +1,7 @@ +test.test\_build module +======================= + +.. automodule:: test.test_build + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_build_options.rst b/docs/reference/rebrickable_api/test.test_build_options.rst new file mode 100644 index 0000000..27612d3 --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_build_options.rst @@ -0,0 +1,7 @@ +test.test\_build\_options module +================================ + +.. automodule:: test.test_build_options + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_color.rst b/docs/reference/rebrickable_api/test.test_color.rst new file mode 100644 index 0000000..779745a --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_color.rst @@ -0,0 +1,7 @@ +test.test\_color module +======================= + +.. automodule:: test.test_color + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_element.rst b/docs/reference/rebrickable_api/test.test_element.rst new file mode 100644 index 0000000..201b618 --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_element.rst @@ -0,0 +1,7 @@ +test.test\_element module +========================= + +.. automodule:: test.test_element + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_error_message.rst b/docs/reference/rebrickable_api/test.test_error_message.rst new file mode 100644 index 0000000..7b06413 --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_error_message.rst @@ -0,0 +1,7 @@ +test.test\_error\_message module +================================ + +.. automodule:: test.test_error_message + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_external_color_id.rst b/docs/reference/rebrickable_api/test.test_external_color_id.rst new file mode 100644 index 0000000..b0413ec --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_external_color_id.rst @@ -0,0 +1,7 @@ +test.test\_external\_color\_id module +===================================== + +.. automodule:: test.test_external_color_id + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_external_color_ids.rst b/docs/reference/rebrickable_api/test.test_external_color_ids.rst new file mode 100644 index 0000000..bf60311 --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_external_color_ids.rst @@ -0,0 +1,7 @@ +test.test\_external\_color\_ids module +====================================== + +.. automodule:: test.test_external_color_ids + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_external_ids.rst b/docs/reference/rebrickable_api/test.test_external_ids.rst new file mode 100644 index 0000000..2d1280a --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_external_ids.rst @@ -0,0 +1,7 @@ +test.test\_external\_ids module +=============================== + +.. automodule:: test.test_external_ids + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_inventory_part.rst b/docs/reference/rebrickable_api/test.test_inventory_part.rst new file mode 100644 index 0000000..6bd0de8 --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_inventory_part.rst @@ -0,0 +1,7 @@ +test.test\_inventory\_part module +================================= + +.. automodule:: test.test_inventory_part + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_lego.rst b/docs/reference/rebrickable_api/test.test_lego.rst new file mode 100644 index 0000000..1ddcd4b --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_lego.rst @@ -0,0 +1,7 @@ +test.test\_lego module +====================== + +.. automodule:: test.test_lego + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_lego_api.rst b/docs/reference/rebrickable_api/test.test_lego_api.rst new file mode 100644 index 0000000..317ce76 --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_lego_api.rst @@ -0,0 +1,7 @@ +test.test\_lego\_api module +=========================== + +.. automodule:: test.test_lego_api + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_lost_part.rst b/docs/reference/rebrickable_api/test.test_lost_part.rst new file mode 100644 index 0000000..469c743 --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_lost_part.rst @@ -0,0 +1,7 @@ +test.test\_lost\_part module +============================ + +.. automodule:: test.test_lost_part + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_moc.rst b/docs/reference/rebrickable_api/test.test_moc.rst new file mode 100644 index 0000000..9bf47f4 --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_moc.rst @@ -0,0 +1,7 @@ +test.test\_moc module +===================== + +.. automodule:: test.test_moc + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_part.rst b/docs/reference/rebrickable_api/test.test_part.rst new file mode 100644 index 0000000..537d0b8 --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_part.rst @@ -0,0 +1,7 @@ +test.test\_part module +====================== + +.. automodule:: test.test_part + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_part_category.rst b/docs/reference/rebrickable_api/test.test_part_category.rst new file mode 100644 index 0000000..8925037 --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_part_category.rst @@ -0,0 +1,7 @@ +test.test\_part\_category module +================================ + +.. automodule:: test.test_part_category + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_part_colors_element.rst b/docs/reference/rebrickable_api/test.test_part_colors_element.rst new file mode 100644 index 0000000..3e48121 --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_part_colors_element.rst @@ -0,0 +1,7 @@ +test.test\_part\_colors\_element module +======================================= + +.. automodule:: test.test_part_colors_element + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_part_colors_list.rst b/docs/reference/rebrickable_api/test.test_part_colors_list.rst new file mode 100644 index 0000000..cd8b33f --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_part_colors_list.rst @@ -0,0 +1,7 @@ +test.test\_part\_colors\_list module +==================================== + +.. automodule:: test.test_part_colors_list + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_part_list.rst b/docs/reference/rebrickable_api/test.test_part_list.rst new file mode 100644 index 0000000..3712eb4 --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_part_list.rst @@ -0,0 +1,7 @@ +test.test\_part\_list module +============================ + +.. automodule:: test.test_part_list + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_part_list_part.rst b/docs/reference/rebrickable_api/test.test_part_list_part.rst new file mode 100644 index 0000000..67410db --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_part_list_part.rst @@ -0,0 +1,7 @@ +test.test\_part\_list\_part module +================================== + +.. automodule:: test.test_part_list_part + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_profile.rst b/docs/reference/rebrickable_api/test.test_profile.rst new file mode 100644 index 0000000..f2402d1 --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_profile.rst @@ -0,0 +1,7 @@ +test.test\_profile module +========================= + +.. automodule:: test.test_profile + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_rewards.rst b/docs/reference/rebrickable_api/test.test_rewards.rst new file mode 100644 index 0000000..cceea7b --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_rewards.rst @@ -0,0 +1,7 @@ +test.test\_rewards module +========================= + +.. automodule:: test.test_rewards + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_set.rst b/docs/reference/rebrickable_api/test.test_set.rst new file mode 100644 index 0000000..a7b768d --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_set.rst @@ -0,0 +1,7 @@ +test.test\_set module +===================== + +.. automodule:: test.test_set + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_set_list.rst b/docs/reference/rebrickable_api/test.test_set_list.rst new file mode 100644 index 0000000..d9472c8 --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_set_list.rst @@ -0,0 +1,7 @@ +test.test\_set\_list module +=========================== + +.. automodule:: test.test_set_list + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_set_list_set.rst b/docs/reference/rebrickable_api/test.test_set_list_set.rst new file mode 100644 index 0000000..7144406 --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_set_list_set.rst @@ -0,0 +1,7 @@ +test.test\_set\_list\_set module +================================ + +.. automodule:: test.test_set_list_set + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_theme.rst b/docs/reference/rebrickable_api/test.test_theme.rst new file mode 100644 index 0000000..51ace2d --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_theme.rst @@ -0,0 +1,7 @@ +test.test\_theme module +======================= + +.. automodule:: test.test_theme + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_users_api.rst b/docs/reference/rebrickable_api/test.test_users_api.rst new file mode 100644 index 0000000..2eceec4 --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_users_api.rst @@ -0,0 +1,7 @@ +test.test\_users\_api module +============================ + +.. automodule:: test.test_users_api + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_api/test.test_users_token_response.rst b/docs/reference/rebrickable_api/test.test_users_token_response.rst new file mode 100644 index 0000000..b06a1b0 --- /dev/null +++ b/docs/reference/rebrickable_api/test.test_users_token_response.rst @@ -0,0 +1,7 @@ +test.test\_users\_token\_response module +======================================== + +.. automodule:: test.test_users_token_response + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_cli/cli.rebrickable_cli.cli.common.rst b/docs/reference/rebrickable_cli/cli.rebrickable_cli.cli.common.rst new file mode 100644 index 0000000..8a7946f --- /dev/null +++ b/docs/reference/rebrickable_cli/cli.rebrickable_cli.cli.common.rst @@ -0,0 +1,7 @@ +cli.rebrickable\_cli.cli.common module +====================================== + +.. automodule:: cli.rebrickable_cli.cli.common + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_cli/cli.rebrickable_cli.cli.lego.rst b/docs/reference/rebrickable_cli/cli.rebrickable_cli.cli.lego.rst new file mode 100644 index 0000000..23e89d3 --- /dev/null +++ b/docs/reference/rebrickable_cli/cli.rebrickable_cli.cli.lego.rst @@ -0,0 +1,7 @@ +cli.rebrickable\_cli.cli.lego module +==================================== + +.. automodule:: cli.rebrickable_cli.cli.lego + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_cli/cli.rebrickable_cli.cli.main.rst b/docs/reference/rebrickable_cli/cli.rebrickable_cli.cli.main.rst new file mode 100644 index 0000000..ca5d735 --- /dev/null +++ b/docs/reference/rebrickable_cli/cli.rebrickable_cli.cli.main.rst @@ -0,0 +1,7 @@ +cli.rebrickable\_cli.cli.main module +==================================== + +.. automodule:: cli.rebrickable_cli.cli.main + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_cli/cli.rebrickable_cli.cli.rst b/docs/reference/rebrickable_cli/cli.rebrickable_cli.cli.rst new file mode 100644 index 0000000..50f1298 --- /dev/null +++ b/docs/reference/rebrickable_cli/cli.rebrickable_cli.cli.rst @@ -0,0 +1,21 @@ +cli.rebrickable\_cli.cli package +================================ + +Submodules +---------- + +.. toctree:: + + cli.rebrickable_cli.cli.common + cli.rebrickable_cli.cli.lego + cli.rebrickable_cli.cli.main + cli.rebrickable_cli.cli.user + cli.rebrickable_cli.cli.users + +Module contents +--------------- + +.. automodule:: cli.rebrickable_cli.cli + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_cli/cli.rebrickable_cli.cli.user.rst b/docs/reference/rebrickable_cli/cli.rebrickable_cli.cli.user.rst new file mode 100644 index 0000000..6cfb3d6 --- /dev/null +++ b/docs/reference/rebrickable_cli/cli.rebrickable_cli.cli.user.rst @@ -0,0 +1,7 @@ +cli.rebrickable\_cli.cli.user module +==================================== + +.. automodule:: cli.rebrickable_cli.cli.user + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_cli/cli.rebrickable_cli.cli.users.rst b/docs/reference/rebrickable_cli/cli.rebrickable_cli.cli.users.rst new file mode 100644 index 0000000..dfb9ac7 --- /dev/null +++ b/docs/reference/rebrickable_cli/cli.rebrickable_cli.cli.users.rst @@ -0,0 +1,7 @@ +cli.rebrickable\_cli.cli.users module +===================================== + +.. automodule:: cli.rebrickable_cli.cli.users + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_cli/cli.rebrickable_cli.rst b/docs/reference/rebrickable_cli/cli.rebrickable_cli.rst new file mode 100644 index 0000000..3fd348e --- /dev/null +++ b/docs/reference/rebrickable_cli/cli.rebrickable_cli.rst @@ -0,0 +1,24 @@ +cli.rebrickable\_cli package +============================ + +Subpackages +----------- + +.. toctree:: + + cli.rebrickable_cli.cli + +Submodules +---------- + +.. toctree:: + + cli.rebrickable_cli.utils + +Module contents +--------------- + +.. automodule:: cli.rebrickable_cli + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_cli/cli.rebrickable_cli.utils.rst b/docs/reference/rebrickable_cli/cli.rebrickable_cli.utils.rst new file mode 100644 index 0000000..c1a6632 --- /dev/null +++ b/docs/reference/rebrickable_cli/cli.rebrickable_cli.utils.rst @@ -0,0 +1,7 @@ +cli.rebrickable\_cli.utils module +================================= + +.. automodule:: cli.rebrickable_cli.utils + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_cli/cli.rst b/docs/reference/rebrickable_cli/cli.rst new file mode 100644 index 0000000..4e8d1ce --- /dev/null +++ b/docs/reference/rebrickable_cli/cli.rst @@ -0,0 +1,17 @@ +cli package +=========== + +Subpackages +----------- + +.. toctree:: + + cli.rebrickable_cli + +Module contents +--------------- + +.. automodule:: cli + :members: + :undoc-members: + :show-inheritance: diff --git a/docs/reference/rebrickable_cli/modules.rst b/docs/reference/rebrickable_cli/modules.rst new file mode 100644 index 0000000..5c2cacf --- /dev/null +++ b/docs/reference/rebrickable_cli/modules.rst @@ -0,0 +1,7 @@ +cli +=== + +.. toctree:: + :maxdepth: 4 + + cli From 1e193e38d463109cf8f2d48bb8146211f08b1a7a Mon Sep 17 00:00:00 2001 From: rienafairefr Date: Tue, 11 Sep 2018 17:18:47 +0200 Subject: [PATCH 16/19] better get_ot_push --- cli/rebrickable_cli/cli/common.py | 52 ++++++++++--------------------- cli/rebrickable_cli/cli/lego.py | 28 +++++++++++------ cli/rebrickable_cli/cli/user.py | 21 ++++++++----- cli/rebrickable_cli/cli/users.py | 9 +++--- 4 files changed, 54 insertions(+), 56 deletions(-) diff --git a/cli/rebrickable_cli/cli/common.py b/cli/rebrickable_cli/cli/common.py index d5a7d62..294e5d4 100644 --- a/cli/rebrickable_cli/cli/common.py +++ b/cli/rebrickable_cli/cli/common.py @@ -24,29 +24,23 @@ def oprint(obj): get_current_context().find_object(State).format.output(obj) -def get_or_push_context_obj(*decorators): - def decorator(fun): - @pass_state - @click.pass_context - @wraps(fun) - def decorated(click_context, state, *args, **kwargs): - for attr in kwargs: - setattr(state, attr, kwargs[attr]) - try: - current_obj = fun(*args, **kwargs) - except: - current_obj = fun(state, *args, **kwargs) - if click_context.invoked_subcommand is None: - oprint(current_obj) - else: - click_context.obj = current_obj - - current = decorated - for dec in decorators: - current = dec(current) - - return current - return decorator +def get_or_push(fun): + @pass_state + @click.pass_context + @wraps(fun) + def decorated(click_context, state, *args, **kwargs): + for attr in kwargs: + setattr(state, attr, kwargs[attr]) + try: + current_obj = fun(*args, **kwargs) + except: + current_obj = fun(state, *args, **kwargs) + if click_context.invoked_subcommand is None: + oprint(current_obj) + else: + click_context.obj = current_obj + + return decorated def object_print(fun): @@ -76,15 +70,3 @@ def decorator(fun): pass_state = click.make_pass_decorator(State) - - -class StateGroup(Group): - def group(self, *args, **kwargs): - def decorated(fun): - return pass_state(fun) - return super(StateGroup, self).group(*args, **kwargs)(decorated) - - def command(self, *args, **kwargs): - def decorated(fun): - return pass_state(fun) - return super(StateGroup, self).command(*args, **kwargs)(decorated) \ No newline at end of file diff --git a/cli/rebrickable_cli/cli/lego.py b/cli/rebrickable_cli/cli/lego.py index 15634b1..930f829 100644 --- a/cli/rebrickable_cli/cli/lego.py +++ b/cli/rebrickable_cli/cli/lego.py @@ -1,8 +1,8 @@ import click from rebrickable_api import LegoApi, Part, PartColorsElement, Color, Element, Moc, PartCategory, Set, Theme -from rebrickable_cli.cli.common import add_typed_subcommands, pass_state, get_or_push_context_obj, \ - object_print, oprint +from rebrickable_cli.cli.common import add_typed_subcommands, pass_state, \ + object_print, oprint, get_or_push @click.group(help='LEGO data (parts, sets, themes, etc.)') @@ -21,7 +21,8 @@ def lego_parts(state): @add_typed_subcommands(Part) @lego.group('part') @pass_state -@get_or_push_context_obj(click.argument('part_num')) +@get_or_push +@click.argument('part_num') def lego_part(state, part_num): return state.api.lego_parts_read(part_num=state.part_num) @@ -36,7 +37,8 @@ def lego_part_colors(state): @add_typed_subcommands(PartColorsElement) @lego_part.group('color') @pass_state -@get_or_push_context_obj(click.argument('color_id', type=int)) +@get_or_push +@click.argument('color_id', type=int) def lego_part_color(state, color_id): return state.api.lego_parts_colors_read(color_id=color_id, part_num=state.part_num) @@ -58,7 +60,8 @@ def lego_colors(state): @add_typed_subcommands(Color) @lego.group('color') @pass_state -@get_or_push_context_obj(click.argument('color_id', type=int)) +@get_or_push +@click.argument('color_id', type=int) def lego_color(state, color_id): return state.api.lego_colors_read(id=color_id) @@ -66,7 +69,8 @@ def lego_color(state, color_id): @add_typed_subcommands(Element) @lego.group('element') @pass_state -@get_or_push_context_obj(click.argument('element_id')) +@get_or_push +@click.argument('element_id') def lego_element(state, element_id): return state.api.lego_elements_read(element_id=element_id) @@ -74,7 +78,8 @@ def lego_element(state, element_id): @add_typed_subcommands(Moc) @lego.group('moc') @pass_state -@get_or_push_context_obj(click.argument('set_num')) +@get_or_push +@click.argument('set_num') def lego_moc(state, set_num): return state.api.lego_mocs_read(set_num=set_num) @@ -96,7 +101,8 @@ def lego_part_categories(state): @add_typed_subcommands(PartCategory) @lego.group('part_category') @pass_state -@get_or_push_context_obj(click.argument('id', type=int)) +@get_or_push +@click.argument('id', type=int) def lego_part_category(state, id): return state.api.lego_part_categories_read(id=id) @@ -110,7 +116,8 @@ def lego_sets(state): @add_typed_subcommands(Set) @lego.group('set') @pass_state -@get_or_push_context_obj(click.argument('set_num')) +@get_or_push +@click.argument('set_num') def lego_set(state, set_num): return state.api.lego_sets_read(set_num=set_num) @@ -146,6 +153,7 @@ def lego_themes(state): @add_typed_subcommands(Theme) @lego.group('theme') @pass_state -@get_or_push_context_obj(click.argument('theme_id')) +@get_or_push +@click.argument('theme_id') def lego_theme(state, theme_id): return state.api.lego_themes_read(id=theme_id) \ No newline at end of file diff --git a/cli/rebrickable_cli/cli/user.py b/cli/rebrickable_cli/cli/user.py index 883ec2a..b214871 100644 --- a/cli/rebrickable_cli/cli/user.py +++ b/cli/rebrickable_cli/cli/user.py @@ -5,7 +5,7 @@ from rebrickable_api import PartList, Profile, SetList, SetListSet, Build, UsersApi from rebrickable_api.rest import ApiException from rebrickable_cli.cli.common import add_typed_subcommands, pass_state, \ - get_or_push_context_obj, object_print + get_or_push, object_print, get_or_push from rebrickable_cli.utils import get_data @@ -24,7 +24,8 @@ def user(state, username): @add_typed_subcommands(PartList) @user.group('partlist') @pass_state -@get_or_push_context_obj(click.argument('list_id', type=int)) +@get_or_push +@click.argument('list_id', type=int) def user_partlist(state, list_id): return state.api.users_partlists_read(user_token=state.user_token, list_id=list_id) @@ -89,7 +90,9 @@ def user_partlist_parts_list(state): @add_typed_subcommands(PartList) @user_partlist.group('part') @pass_state -@get_or_push_context_obj(click.argument('part_num'), click.argument('color_id', type=int)) +@get_or_push +@click.argument('color_id', type=int) +@click.argument('part_num') def user_partlist_part(state, color_id, part_num): return state.api.users_partlists_parts_read(user_token=state.user_token, color_id=color_id, list_id=state.list_id, @@ -144,7 +147,8 @@ def user_setlists_list(state): @add_typed_subcommands(SetList) @user.group('setlist') @pass_state -@get_or_push_context_obj(click.argument('list_id', type=int)) +@get_or_push +@click.argument('list_id', type=int) def user_setlist(state, list_id): return state.api.users_setlists_read(user_token=state.user_token, list_id=list_id) @@ -191,7 +195,8 @@ def user_setlist_sets_list(state): @add_typed_subcommands(SetListSet) @user_setlist.group('set') @pass_state -@get_or_push_context_obj(click.argument('set_num')) +@get_or_push +@click.argument('set_num') def user_setlist_set(state, set_num): return state.api.users_setlists_sets_read(user_token=state.user_token, list_id=state.list_id, set_num=set_num) @@ -271,7 +276,8 @@ def user_sets_list(state, *args, **kwargs): @add_typed_subcommands(SetListSet) @user.group('set') @pass_state -@get_or_push_context_obj(click.argument('set_num')) +@get_or_push +@click.argument('set_num') def user_set(state, set_num): return state.api.users_sets_read(user_token=state.user_token, set_num=set_num) @@ -328,7 +334,8 @@ def user_allparts(state): @add_typed_subcommands(Build) @user.group('build') @pass_state -@get_or_push_context_obj(click.argument('set_num')) +@get_or_push +@click.argument('set_num') def user_build(state, set_num): return state.api.users_build_read(user_token=state.user_token, set_num=set_num) diff --git a/cli/rebrickable_cli/cli/users.py b/cli/rebrickable_cli/cli/users.py index 7eaebb7..b51ceec 100644 --- a/cli/rebrickable_cli/cli/users.py +++ b/cli/rebrickable_cli/cli/users.py @@ -5,7 +5,7 @@ from rebrickable_api import UsersApi, Badge from rebrickable_api.rest import ApiException from rebrickable_cli.cli.common import object_print, add_typed_subcommands, \ - get_or_push_context_obj, pass_state + pass_state, get_or_push from rebrickable_cli.utils import get_data, write_data, DATA_PATH @@ -25,9 +25,10 @@ def users_badges_list(state): @add_typed_subcommands(Badge) @users.group('badge') @pass_state -@get_or_push_context_obj(click.argument('id', type=int)) -def users_badge(state, id): - return state.api.users_badges_read(id=id) +@get_or_push +@click.argument('badge_id', type=int) +def users_badge(state, badge_id): + return state.api.users_badges_read(id=badge_id) def create_auth(state, username=None): From 791a6aeb116587ae876333e1c5ad4b3b193b7b70 Mon Sep 17 00:00:00 2001 From: rienafairefr Date: Tue, 11 Sep 2018 17:18:54 +0200 Subject: [PATCH 17/19] refactor tests --- scripts/cli_results.py | 75 ----------------- tests/{lego_cli => cli}/__init__.py | 0 .../test_cli.py => cli/test_lego.py} | 47 ++++++----- tests/{test_cli.py => cli/test_main.py} | 82 +++++++++--------- tests/{ => cli}/test_models_integration.py | 0 .../test_user.py} | 83 +++++-------------- tests/cli/test_users.py | 16 ++++ .../{test_cli_utils.py => cli/test_utils.py} | 30 +++++-- tests/utils.py | 31 +++++++ 9 files changed, 155 insertions(+), 209 deletions(-) delete mode 100644 scripts/cli_results.py rename tests/{lego_cli => cli}/__init__.py (100%) rename tests/{lego_cli/test_cli.py => cli/test_lego.py} (77%) rename tests/{test_cli.py => cli/test_main.py} (89%) rename tests/{ => cli}/test_models_integration.py (100%) rename tests/{test_cli_integration.py => cli/test_user.py} (64%) create mode 100644 tests/cli/test_users.py rename tests/{test_cli_utils.py => cli/test_utils.py} (64%) create mode 100644 tests/utils.py diff --git a/scripts/cli_results.py b/scripts/cli_results.py deleted file mode 100644 index 46131d0..0000000 --- a/scripts/cli_results.py +++ /dev/null @@ -1,75 +0,0 @@ -'lego_colors' -from inspect import getmembers -import random -import click -from click.testing import CliRunner - -from rebrickable import cli, LegoApi -from rebrickable.cli import get_api_client, get_users_context - -alldefs = getmembers(cli) -random.shuffle(alldefs) -client = get_api_client() -users_context = get_users_context(client) -lego_api = LegoApi(client) -runner = CliRunner() - -test_args = { - 'lego_mocs_read': ['MOC-4528'], - 'users_partlists_parts_list': ['66871'], - 'users_partlists_parts_read': ['8', '40480', '6587'], - 'users_partlists_read': ['40476'], - 'users_setlists_read': ['161396'], - 'users_setlists_sets_list': ['161396'], - 'users_setlists_sets_read': ['161396', '41116-1'], - 'users_sets_read': ['5866-1'], - 'users_build_read': ['75192-1'], - 'lego_sets_read': ['75192-1'], - 'lego_elements_read': ['4297717'] -} - -failing = [ - 'users_partlists_delete', - 'users_setlists_partial_update', - 'users_setlists_delete', - 'users_setlists_sets_delete', - 'users_setlists_sets_create', - 'users_token_create', - 'users_setlists_sets_update', - 'users_sets_sync_create', - 'users_lost_parts_delete', - 'users_partlists_partial_update', - 'users_sets_create', - 'users_setlists_update', - 'users_setlists_sets_partial_update', - 'users_partlists_update', - 'users_partlists_parts_update', - 'users_partlists_parts_create', - 'users_sets_delete', - 'users_partlists_parts_delete', - 'users_sets_update', -] - -print('[') -for (name, fun) in alldefs: - if name == 'register': - continue - if name == 'users_login': - continue - if name not in failing: - continue - - if isinstance(fun, click.Command) and not isinstance(fun, click.Group): - if name.startswith('users'): - obj = users_context - elif name.startswith('lego'): - obj = lego_api - - if name in test_args: - args = test_args[name] - else: - args = ['1' for param in fun.params] - result = runner.invoke(fun, obj=obj, args=args) - if result.exit_code != 0: - print('\'' + name + '\',') -print(']') diff --git a/tests/lego_cli/__init__.py b/tests/cli/__init__.py similarity index 100% rename from tests/lego_cli/__init__.py rename to tests/cli/__init__.py diff --git a/tests/lego_cli/test_cli.py b/tests/cli/test_lego.py similarity index 77% rename from tests/lego_cli/test_cli.py rename to tests/cli/test_lego.py index b7f6f37..0199cc2 100644 --- a/tests/lego_cli/test_cli.py +++ b/tests/cli/test_lego.py @@ -1,12 +1,14 @@ from __future__ import print_function +import pytest + from rebrickable_cli.cli.common import State from rebrickable_cli.cli.lego import lego_colors, lego_color, lego_element, lego_part_categories, lego_part_category, \ lego_parts, lego_sets, lego_themes, lego_theme, lego_set, lego_set_alternates, lego_set_parts, lego_set_sets, \ lego_part_colors, lego_part, lego_part_color, lego_part_color_sets, lego_moc_parts, lego_moc from rebrickable_cli.cli.main import OutputFormatter -from tests.test_cli_integration import parametrized, do_test +from tests.utils import parametrized, do_test lego_operations = [ (lego_colors, 'lego_colors_list', [], {}), @@ -21,11 +23,19 @@ ] -@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], lego_operations) -def test_lego_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api): - state = State(format=OutputFormatter(output=print), api=mocked_lego_api) +@pytest.fixture +def mocked_state(mocked_lego_api): + return State(format=OutputFormatter(output=print), + api=mocked_lego_api, + set_num='75192-1', + part_num='3004', + color_id=45 + ) - do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api, state) + +@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], lego_operations) +def test_lego_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_state): + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_state) lego_set_operations = [ @@ -37,12 +47,10 @@ def test_lego_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocke @parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], lego_set_operations) -def test_lego_set_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api): - state = State(format=OutputFormatter(output=print), api=mocked_lego_api, set_num='75192-1') - +def test_lego_set_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_state): call_kwargs['set_num'] = '75192-1' - do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api, state) + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_state) lego_part_operations = [ @@ -52,12 +60,10 @@ def test_lego_set_entrypoints(cli_func, method, cli_args, call_kwargs, runner, m @parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], lego_part_operations) -def test_lego_part_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api): - state = State(OutputFormatter(output=print), api=mocked_lego_api, part_num='3004') - +def test_lego_part_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_state): call_kwargs['part_num'] = '3004' - do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api, state) + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_state) lego_part_color_operations = [ @@ -67,13 +73,11 @@ def test_lego_part_entrypoints(cli_func, method, cli_args, call_kwargs, runner, @parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], lego_part_color_operations) -def test_lego_part_color_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api): - state = State(format=OutputFormatter(output=print), api=mocked_lego_api, part_num='3020', color_id=45) - - call_kwargs['part_num'] = '3020' +def test_lego_part_color_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_state): + call_kwargs['part_num'] = '3004' call_kwargs['color_id'] = 45 - do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api, state) + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_state) lego_moc_operations = [ @@ -83,9 +87,8 @@ def test_lego_part_color_entrypoints(cli_func, method, cli_args, call_kwargs, ru @parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], lego_moc_operations) -def test_lego_moc_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api): - state = State(format=OutputFormatter(output=print), api=mocked_lego_api, set_num='MOC-5634') - +def test_lego_moc_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_state): + mocked_state.set_num = 'MOC-5634' call_kwargs['set_num'] = 'MOC-5634' - do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_lego_api, state) + do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_state) diff --git a/tests/test_cli.py b/tests/cli/test_main.py similarity index 89% rename from tests/test_cli.py rename to tests/cli/test_main.py index b90460c..269873d 100644 --- a/tests/test_cli.py +++ b/tests/cli/test_main.py @@ -3,13 +3,13 @@ """Tests for `pyrebrickable` package.""" import decorator +import pytest from mock import patch, Mock -from functools import wraps -from rebrickable_api import Part, Color, Element, Moc, LegoApi, PartColorsElement +from rebrickable_api import Part, Color, Element, Moc, LegoApi, PartColorsElement, UsersApi from rebrickable_api.rest import ApiException -from rebrickable_cli.cli.common import pass_state +from rebrickable_cli.cli.common import pass_state, State from rebrickable_cli.cli.lego import lego, lego_part, lego_part_color, lego_color, lego_element, lego_moc from rebrickable_cli.cli.main import main from rebrickable_cli.cli.user import user @@ -25,12 +25,6 @@ def test_command_line_interface(runner): assert 'Show this message and exit.' in help_result.output -@main.command(name='test') -@pass_state -def command_dummy(obj): - pass - - def mocked_data(value=None): def get_(): return value @@ -46,23 +40,9 @@ def decorated(*a, **kwa): return decorator.decorator(wrapper) -def with_mocked_api(): - def wrapper(fun, *args, **kwargs): - def get_part(part_num, *a, **kwa): - return Part(part_num=part_num) - - @wraps(fun) - @patch.object(LegoApi, 'lego_parts_read', Mock(side_effect=get_part)) - def wrapper(*a, **kwa): - return fun(*a, **kwa) - - return wrapper - return decorator.decorator(wrapper) - -@mocked_data({'api_key': 'api_key_value'}) -def test_main_command_pass_obj_valid(runner): - result = runner.invoke(main, ['test']) - assert result.exception is None +@main.command(name='test') +def command_dummy(): + pass @mocked_data({}) @@ -71,25 +51,47 @@ def test_main_command_pass_obj_invalid(runner): assert result.exception is not None -@user.command(name='test') -@pass_state -def user_test(state): - assert state.user_token == 'user_token_value' +@mocked_data(None) +def test_users_command_pass_obj_invalid(runner): + result = runner.invoke(main, ['user', 'test']) + assert result.exception is not None + + +@mocked_data({'api_key': 'api_key_value'}) +def test_main_command_pass_obj_valid(runner): + result = runner.invoke(main, ['test']) + assert result.exception is None @mocked_data({'api_key': 'api_key_value', 'users': {'%%default%%': {'token': 'user_token_value'}}}) def test_users_command_pass_obj_valid(runner): + @user.command(name='test') + @pass_state + def user_test(state): + assert isinstance(state.api, UsersApi) + assert state.user_token == 'user_token_value' + result = runner.invoke(main, ['user', 'test']) assert result.exception is None -@mocked_data(None) -def test_users_command_pass_obj_invalid(runner): - result = runner.invoke(main, ['user', 'test']) - assert result.exception is not None +@mocked_data({'api_key': 'api_key_value', 'users': {'username': {'token': 'user_token_value'}}}) +def test_users_command_pass_obj_valid(runner): + @user.command(name='test') + @pass_state + def user_test(state): + assert isinstance(state.api, UsersApi) + assert state.user_token == 'user_token_value' + + result = runner.invoke(main, ['user', '-u', 'username', 'test']) + assert result.exception is None + + +@pytest.fixture +def mocked_state(): + return State() -@patch('rebrickable_cli.cli.main.get_api_client', new=Mock()) @patch.object(LegoApi, 'lego_parts_read', Mock(return_value=Part(part_num='3002'))) def test_lego_part_command_pass_obj(runner): @lego_part.command(name='test') @@ -151,14 +153,14 @@ def lego_moc_test(state): assert result.exception is None -@lego.command(name='test') -def lego_test(): - pass - - @patch('rebrickable_cli.cli.main.get_api_client', new=Mock()) @mocked_data({'api_key': 'api_key_value'}) def test_lego_command_pass_obj_valid(runner): + @lego.command(name='test') + @pass_state + def lego_test(state): + assert isinstance(state.api, LegoApi) + result = runner.invoke(main, ['lego', 'test']) assert result.exception is None diff --git a/tests/test_models_integration.py b/tests/cli/test_models_integration.py similarity index 100% rename from tests/test_models_integration.py rename to tests/cli/test_models_integration.py diff --git a/tests/test_cli_integration.py b/tests/cli/test_user.py similarity index 64% rename from tests/test_cli_integration.py rename to tests/cli/test_user.py index ea588af..31e6417 100644 --- a/tests/test_cli_integration.py +++ b/tests/cli/test_user.py @@ -2,39 +2,9 @@ from six import StringIO -import pytest -from click import Context, Command - -from rebrickable_cli.cli.lego import * from rebrickable_cli.cli.main import * from rebrickable_cli.cli.user import * -from rebrickable_cli.cli.users import * - - -def parametrized(*args, **kwargs): - def decorator(fun): - if 'ids' not in kwargs: - def get_id(param): - if isinstance(param, Command): - return param.callback.__name__ - return str(param) - - kwargs['ids'] = get_id - return pytest.mark.parametrize(*args, **kwargs)(fun) - - return decorator - - -def do_test(cli_func, method, cli_args, call_kwargs, runner, api, context): - mocked_method = getattr(api, method) - mocked_method.return_value = 'stuff' - result = runner.invoke(cli_func, cli_args, obj=context) - if result.exit_code != 0: - print(result.output) - pass - mocked_method.assert_called_with(**call_kwargs) - assert 'stuff\n' == result.output - +from tests.utils import parametrized, do_test users_operations = [ (user_partlists_create, 'users_partlists_create', ['test'], {'name': 'test'}), @@ -59,27 +29,14 @@ def do_test(cli_func, method, cli_args, call_kwargs, runner, api, context): @parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], users_operations) -def test_users_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): +def test_user_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): state = State(format=OutputFormatter(output=print), api=mocked_users_api, user_token='abcdef') call_kwargs['user_token'] = 'abcdef' - do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api, state) - - -users_no_token_operations = [ - (users_badges_list, 'users_badges_list', [], {}), - (users_badge, 'users_badges_read', ['12345'], {'id': 12345}), -] - - -@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], users_no_token_operations) -def test_users_no_token_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): - state = State(format=OutputFormatter(output=print), api=mocked_users_api, user_token='abcdef') - - do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api, state) + do_test(cli_func, method, cli_args, call_kwargs, runner, state) -users_partlist_operations = [ +user_partlist_operations = [ (user_partlist_partial_update, 'users_partlists_partial_update', [], {}), (user_partlist_delete, 'users_partlists_delete', [], {}), (user_partlist_parts_create, 'users_partlists_parts_create', ['3004', '4', '45'], @@ -91,17 +48,17 @@ def test_users_no_token_entrypoints(cli_func, method, cli_args, call_kwargs, run ] -@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], users_partlist_operations) -def test_users_partlist_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): +@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], user_partlist_operations) +def test_user_partlist_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): state = State(format=OutputFormatter(output=print), api=mocked_users_api, user_token='abcdef', list_id=987654321) call_kwargs['list_id'] = 987654321 call_kwargs['user_token'] = 'abcdef' - do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api, state) + do_test(cli_func, method, cli_args, call_kwargs, runner, state) -users_partlist_part_operations = [ +user_partlist_part_operations = [ (user_partlist_part, 'users_partlists_parts_read', ['45', '3004'], {'color_id': 45}), (user_partlist_part_update, 'users_partlists_parts_update', ['475'], @@ -109,8 +66,8 @@ def test_users_partlist_entrypoints(cli_func, method, cli_args, call_kwargs, run ] -@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], users_partlist_part_operations) -def test_users_partlist_part_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): +@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], user_partlist_part_operations) +def test_user_partlist_part_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): state = State(format=OutputFormatter(output=print), api=mocked_users_api, user_token='abcdef', list_id=987654321, color_id=45, part_num='3004') call_kwargs['color_id'] = 45 @@ -118,10 +75,10 @@ def test_users_partlist_part_entrypoints(cli_func, method, cli_args, call_kwargs call_kwargs['list_id'] = 987654321 call_kwargs['user_token'] = 'abcdef' - do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api, state) + do_test(cli_func, method, cli_args, call_kwargs, runner, state) -users_setlist_operations = [ +user_setlist_operations = [ (user_setlist, 'users_setlists_read', ['987654321'], {}), (user_setlist_delete, 'users_setlists_delete', [], {}), (user_setlist_sets_create, 'users_setlists_sets_create', ['1234-1'], {'set_num': '1234-1'}), @@ -131,17 +88,17 @@ def test_users_partlist_part_entrypoints(cli_func, method, cli_args, call_kwargs ] -@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], users_setlist_operations) -def test_users_setlist_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): +@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], user_setlist_operations) +def test_user_setlist_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): state = State(format=OutputFormatter(output=print), api=mocked_users_api, user_token='abcdef', list_id=987654321) call_kwargs['list_id'] = 987654321 call_kwargs['user_token'] = 'abcdef' - do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api, state) + do_test(cli_func, method, cli_args, call_kwargs, runner, state) -users_setlist_set_operations = [ +user_setlist_set_operations = [ (user_setlist_set_delete, 'users_setlists_sets_delete', [], {}), (user_setlist_set_partial_update, 'users_setlists_sets_partial_update', ['1357-1'], {}), (user_setlist_set, 'users_setlists_sets_read', ['1357-1'], {}), @@ -149,15 +106,15 @@ def test_users_setlist_entrypoints(cli_func, method, cli_args, call_kwargs, runn ] -@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], users_setlist_set_operations) -def test_users_setlist_set_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): +@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], user_setlist_set_operations) +def test_user_setlist_set_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): state = State(format=OutputFormatter(output=print), api=mocked_users_api, user_token='abcdef', list_id=987654321, set_num='1357-1') call_kwargs['list_id'] = 987654321 call_kwargs['user_token'] = 'abcdef' call_kwargs['set_num'] = '1357-1' - do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api, state) + do_test(cli_func, method, cli_args, call_kwargs, runner, state) users_set_operations = [ @@ -174,4 +131,4 @@ def test_users_set_entrypoints(cli_func, method, cli_args, call_kwargs, runner, call_kwargs['set_num'] = '75192-1' call_kwargs['user_token'] = 'abcdef' - do_test(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api, state) + do_test(cli_func, method, cli_args, call_kwargs, runner, state) diff --git a/tests/cli/test_users.py b/tests/cli/test_users.py new file mode 100644 index 0000000..79417dd --- /dev/null +++ b/tests/cli/test_users.py @@ -0,0 +1,16 @@ +from rebrickable_cli.cli.common import State +from rebrickable_cli.cli.main import OutputFormatter +from rebrickable_cli.cli.users import users_badges_list, users_badge +from tests.utils import parametrized, do_test + +users_no_token_operations = [ + (users_badges_list, 'users_badges_list', [], {}), + (users_badge, 'users_badges_read', ['12345'], {'id': 12345}), +] + + +@parametrized(['cli_func', 'method', 'cli_args', 'call_kwargs'], users_no_token_operations) +def test_users_no_token_entrypoints(cli_func, method, cli_args, call_kwargs, runner, mocked_users_api): + state = State(format=OutputFormatter(output=print), api=mocked_users_api, user_token='abcdef') + + do_test(cli_func, method, cli_args, call_kwargs, runner, state) \ No newline at end of file diff --git a/tests/test_cli_utils.py b/tests/cli/test_utils.py similarity index 64% rename from tests/test_cli_utils.py rename to tests/cli/test_utils.py index 019c9a2..e75fcae 100644 --- a/tests/test_cli_utils.py +++ b/tests/cli/test_utils.py @@ -3,21 +3,27 @@ import mock from rebrickable_cli.cli.main import get_api_client +from rebrickable_cli.cli.user import get_user_token from rebrickable_cli.utils import get_data, write_data -def test_data(): - api_key = 'nice_api_key' - users_token = 'nice_users_token' - read_data_dict = { - 'api_key': api_key, - 'users': { - '%%default%%': { - 'token': users_token - } +api_key = 'nice_api_key' +user_token = 'user_token' +other_user_token = 'other_user_token' +read_data_dict = { + 'api_key': api_key, + 'users': { + '%%default%%': { + 'token': user_token + }, + 'username': { + 'token': other_user_token } } +} + +def test_data(): m = mock.mock_open(read_data=json.dumps(read_data_dict)) with mock.patch('{}.open'.format('rebrickable_cli.utils'), m, create=True): @@ -48,3 +54,9 @@ def test_write_data(tmpdir): data2 = get_data(p) assert data2.items() == data.items() + + +@mock.patch('rebrickable_cli.cli.user.get_data', return_value=read_data_dict) +def test_get_user_token(mocked): + assert get_user_token() == user_token + assert get_user_token('username') == other_user_token diff --git a/tests/utils.py b/tests/utils.py new file mode 100644 index 0000000..46be3ff --- /dev/null +++ b/tests/utils.py @@ -0,0 +1,31 @@ +from __future__ import print_function + +import pytest +from click import Command + + +def parametrized(*args, **kwargs): + def decorator(fun): + if 'ids' not in kwargs: + def get_id(param): + if isinstance(param, Command): + return param.callback.__name__ + return str(param) + + kwargs['ids'] = get_id + return pytest.mark.parametrize(*args, **kwargs)(fun) + + return decorator + + +def do_test(cli_func, method, cli_args, call_kwargs, runner, state): + mocked_method = getattr(state.api, method) + mocked_method.return_value = 'stuff' + result = runner.invoke(cli_func, cli_args, obj=state) + if result.exit_code != 0: + print(result.output) + pass + mocked_method.assert_called_with(**call_kwargs) + assert 'stuff\n' == result.output + + From 1a33f6890d50331714620a115c695bb688cf0b38 Mon Sep 17 00:00:00 2001 From: rienafairefr Date: Mon, 17 Sep 2018 15:26:15 +0200 Subject: [PATCH 18/19] print_function --- tests/cli/test_models_integration.py | 4 +++- tests/cli/test_users.py | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/cli/test_models_integration.py b/tests/cli/test_models_integration.py index 48dd994..c7cb8d3 100644 --- a/tests/cli/test_models_integration.py +++ b/tests/cli/test_models_integration.py @@ -1,3 +1,5 @@ +from __future__ import print_function + import json from pprint import pprint @@ -5,7 +7,7 @@ import six from jsondiff import diff -from rebrickable_api import LegoApi, ApiClient, UsersApi +from rebrickable_api import LegoApi, UsersApi from rebrickable_cli.cli.common import State from rebrickable_cli.cli.user import get_user_token from rebrickable_cli.cli.main import get_api_client diff --git a/tests/cli/test_users.py b/tests/cli/test_users.py index 79417dd..dba3f02 100644 --- a/tests/cli/test_users.py +++ b/tests/cli/test_users.py @@ -1,3 +1,5 @@ +from __future__ import print_function + from rebrickable_cli.cli.common import State from rebrickable_cli.cli.main import OutputFormatter from rebrickable_cli.cli.users import users_badges_list, users_badge From 46179db0d5db8670434286df6a2070abd90e4f3e Mon Sep 17 00:00:00 2001 From: rienafairefr Date: Mon, 17 Sep 2018 15:31:20 +0200 Subject: [PATCH 19/19] mocked api_client --- tests/cli/test_main.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/cli/test_main.py b/tests/cli/test_main.py index 269873d..7ddb196 100644 --- a/tests/cli/test_main.py +++ b/tests/cli/test_main.py @@ -92,6 +92,7 @@ def mocked_state(): return State() +@patch('rebrickable_cli.cli.main.get_api_client', new=Mock()) @patch.object(LegoApi, 'lego_parts_read', Mock(return_value=Part(part_num='3002'))) def test_lego_part_command_pass_obj(runner): @lego_part.command(name='test')