def __init__(self, config=None): # Setup Logging self.logger = logging.getLogger(__name__) formatter = logging.Formatter( "%(asctime)s - %(name)s - %(levelname)s - %(message)s") fh = logging.handlers.RotatingFileHandler(f"log_pymkm.log", maxBytes=500000, backupCount=2) fh.setLevel(logging.WARNING) fh.setFormatter(formatter) self.logger.addHandler(fh) sh = logging.StreamHandler() sh.setLevel(logging.ERROR) # This gets outputted to stdout sh.setFormatter(formatter) self.logger.addHandler(sh) self.logger.debug(">> Loading config file") try: with open("config.json", "r") as config_file: self.config = json.load(config_file) except FileNotFoundError: self.logger.error( "You must copy config_template.json to config.json and populate the fields." ) sys.exit(0) fh.setLevel(self.config["log_level"]) self.logger.setLevel(self.config["log_level"]) self.api = PyMkmApi(config=self.config) print("Fetching Cardmarket account data...") self.account = self.get_account_data() self.wantlists = self.api.get_wantslists()
def test_file_not_found2(self): open_name = '%s.open' % __name__ with patch("builtins.open", mock_open(read_data="data")) as mocked_open: mocked_open.side_effect = FileNotFoundError # Assert that an error is logged with self.assertRaises(SystemExit): with self.assertLogs(level='ERROR') as cm: PyMkmApi() log_record_level = cm.records[0].levelname self.assertEqual(log_record_level, 'ERROR')
def __init__(self, config=None): if (config == None): logging.debug(">> Loading config file") try: self.config = json.load(open('config.json')) except FileNotFoundError: logging.error( "You must copy config_template.json to config.json and populate the fields.") sys.exit(0) else: self.config = config self.api = PyMkmApi(config=self.config)
def setUp(self): super(TestPyMkmApiCalls, self).setUp() self.api = PyMkmApi(self.config)
class TestPyMkmApiCalls(TestCommon): api = None def setUp(self): super(TestPyMkmApiCalls, self).setUp() self.api = PyMkmApi(self.config) def test_file_not_found2(self): open_name = '%s.open' % __name__ with patch("builtins.open", mock_open(read_data="data")) as mocked_open: mocked_open.side_effect = FileNotFoundError # Assert that an error is logged with self.assertRaises(SystemExit): with self.assertLogs(level='ERROR') as cm: PyMkmApi() log_record_level = cm.records[0].levelname self.assertEqual(log_record_level, 'ERROR') def test_get_account(self): mock_oauth = Mock(spec=OAuth1Session) mock_oauth.get = MagicMock( return_value=self.MockResponse("test", 200, 'testing ok')) self.assertEqual(self.api.get_account(mock_oauth), "test") mock_oauth.get.assert_called() mock_oauth.get = MagicMock( return_value=self.MockResponse("", 401, 'Unauthorized')) with self.assertLogs(level='ERROR') as cm: self.api.get_account(mock_oauth) self.assertGreater(len(cm.records), 0) def test_get_stock(self): articles_response = "{{'article': {}}}".format( TestCommon.fake_articles_result).replace("'", '"') articles_response_json = json.loads(articles_response) mock_oauth = Mock(spec=OAuth1Session) mock_oauth.get = MagicMock(return_value=self.MockResponse( articles_response_json, 200, 'testing ok')) self.assertEqual( self.api.get_stock(None, mock_oauth)[0]['comments'], "x") def test_get_games(self): test_json = json.loads('{"test": "test"}') mock_oauth = Mock(spec=OAuth1Session) mock_oauth.get = MagicMock( return_value=self.MockResponse(test_json, 200, 'testing ok')) self.assertEqual(self.api.get_games(mock_oauth), test_json) def test_get_expansions(self): test_json = json.loads('{"test": "test"}') mock_oauth = Mock(spec=OAuth1Session) mock_oauth.get = MagicMock( return_value=self.MockResponse(test_json, 200, 'testing ok')) game_id = 1 self.assertEqual(self.api.get_expansions(game_id, mock_oauth), test_json) def test_get_cards_in_expansion(self): test_json = json.loads('{"test": "test"}') mock_oauth = Mock(spec=OAuth1Session) mock_oauth.get = MagicMock( return_value=self.MockResponse(test_json, 200, 'testing ok')) expansion_id = 1 self.assertEqual( self.api.get_cards_in_expansion(expansion_id, mock_oauth), test_json) def test_get_product(self): test_json = json.loads('{"test": "test"}') mock_oauth = Mock(spec=OAuth1Session) mock_oauth.get = MagicMock( return_value=self.MockResponse(test_json, 200, 'testing ok')) product_id = 1 self.assertEqual(self.api.get_product(product_id, mock_oauth), test_json) def test_find_product(self): mock_oauth = Mock(spec=OAuth1Session) mock_oauth.get = MagicMock(return_value=self.MockResponse( TestCommon.fake_product, 200, 'testing ok')) search_string = 'test' result = self.api.find_product(search_string, mock_oauth) self.assertEqual(result, TestCommon.fake_product) def test_find_stock_article(self): articles_response = "{{'article': {}}}".format( TestCommon.fake_articles_result).replace("'", '"') articles_response_json = json.loads(articles_response) mock_oauth = Mock(spec=OAuth1Session) mock_oauth.get = MagicMock(return_value=self.MockResponse( articles_response_json, 200, 'testing ok')) name = 'test' game_id = 1 result = self.api.find_stock_article(name, game_id, mock_oauth) self.assertEqual(result[0]['comments'], "x") def test_get_articles_in_shoppingcarts(self): test_json = json.loads('{"test": "test"}') mock_oauth = Mock(spec=OAuth1Session) mock_oauth.get = MagicMock( return_value=self.MockResponse(test_json, 200, 'testing ok')) self.assertEqual(self.api.get_articles_in_shoppingcarts(mock_oauth), test_json) def test_get_articles(self): articles_response = "{{'article': {}}}".format( TestCommon.fake_articles_result).replace("'", '"') articles_response_json = json.loads(articles_response) mock_oauth = Mock(spec=OAuth1Session) mock_oauth.get = MagicMock(return_value=self.MockResponse( articles_response_json, 200, 'testing ok')) product_id = 1 result = self.api.get_articles(product_id, 0, mock_oauth) self.assertEqual(result[0]['comments'], "x") mock_oauth.get = MagicMock(return_value=self.MockResponse( articles_response_json, 206, 'partial content')) product_id = 1 result = self.api.get_articles(product_id, 0, mock_oauth) self.assertEqual(result[0]['comments'], "x") def test_find_user_articles(self): articles_response = "{{'article': {}}}".format( TestCommon.fake_articles_result).replace("'", '"') articles_response_json = json.loads(articles_response) mock_oauth = Mock(spec=OAuth1Session) mock_oauth.get = MagicMock(return_value=self.MockResponse( articles_response_json, 200, 'testing ok')) user_id = 1 game_id = 1 result = self.api.find_user_articles(user_id, game_id, 0, mock_oauth) self.assertEqual(result[0]['comments'], "x") mock_oauth.get = MagicMock(return_value=self.MockResponse( articles_response_json, 206, 'partial content')) result = self.api.find_user_articles(user_id, game_id, 0, mock_oauth) self.assertEqual(result[0]['comments'], "x") def test_set_vacation_status(self): mock_oauth = Mock(spec=OAuth1Session) mock_oauth.put = MagicMock(return_value=self.MockResponse( TestCommon.fake_account_data, 200, 'testing ok')) vacation_status = True result = self.api.set_vacation_status(vacation_status, mock_oauth) self.assertEqual(result['message'], 'Successfully set the account on vacation.') self.assertEqual(result['account']['onVacation'], str(vacation_status).lower()) def test_set_display_language(self): mock_oauth = Mock(spec=OAuth1Session) mock_oauth.put = MagicMock(return_value=self.MockResponse( TestCommon.fake_account_data, 200, 'testing ok')) display_language = 1 result = self.api.set_display_language(display_language, mock_oauth) self.assertEqual(result['account']['idDisplayLanguage'], str(display_language).lower()) def test_add_stock(self): mock_oauth = Mock(spec=OAuth1Session) mock_oauth.post = MagicMock(return_value=self.MockResponse( TestCommon.fake_stock, 200, 'testing ok')) result = self.api.add_stock(TestCommon.fake_stock, mock_oauth) self.assertEqual(len(result), 3) def test_set_stock(self): mock_oauth = Mock(spec=OAuth1Session) mock_oauth.put = MagicMock(return_value=self.MockResponse( TestCommon.fake_stock, 200, 'testing ok')) result = self.api.set_stock(TestCommon.fake_stock, mock_oauth) self.assertEqual(len(result), 3) def test_delete_stock(self): mock_oauth = Mock(spec=OAuth1Session) mock_oauth.delete = MagicMock(return_value=self.MockResponse( TestCommon.fake_stock, 200, 'testing ok')) result = self.api.delete_stock(TestCommon.fake_stock, mock_oauth) self.assertEqual(len(result), 3)
class BuywizardApp: logger = None def __init__(self, config=None): # Setup Logging self.logger = logging.getLogger(__name__) formatter = logging.Formatter( "%(asctime)s - %(name)s - %(levelname)s - %(message)s") fh = logging.handlers.RotatingFileHandler(f"log_pymkm.log", maxBytes=500000, backupCount=2) fh.setLevel(logging.WARNING) fh.setFormatter(formatter) self.logger.addHandler(fh) sh = logging.StreamHandler() sh.setLevel(logging.ERROR) # This gets outputted to stdout sh.setFormatter(formatter) self.logger.addHandler(sh) self.logger.debug(">> Loading config file") try: with open("config.json", "r") as config_file: self.config = json.load(config_file) except FileNotFoundError: self.logger.error( "You must copy config_template.json to config.json and populate the fields." ) sys.exit(0) fh.setLevel(self.config["log_level"]) self.logger.setLevel(self.config["log_level"]) self.api = PyMkmApi(config=self.config) print("Fetching Cardmarket account data...") self.account = self.get_account_data() self.wantlists = self.api.get_wantslists() def start(self, args=None): print( f"\nLogged in as: {self.account['name']['firstName']} {self.account['name']['lastName']} ({self.account['username']})" ) # print("\nWhich wantlist would you like to optimize?\n") # for i, list in enumerate(self.wantlists): # print(f"\t[{i}]: {list['name']} ({list['itemCount']} cards)") # choice = int(input("\nEnter your choice: ")) # os.system("clear") # # self.optimize_wantlist(choice) self.optimize_wantlist(0) def get_account_data(self): return self.api.get_account()["account"] def async_get_retry(self, item_type, item_id_list, **kwargs): print(f"Async fetching: {item_type}") ret_list = [None] * len(item_id_list) to_find = item_id_list.copy() round = 1 while len([x for x in ret_list if x is not None]) < len(item_id_list): print(f"Fetch round {round}: {len(to_find)} items left") round += 1 results = self.api.get_items_async(item_type=item_type, item_id_list=to_find, **kwargs) for ind in range(len(ret_list)): if (ret_list[ind] is None) and (len(results) > 0): ret_list[ind] = results.pop(0) if ret_list[ind] is not None: to_find.pop(0) return ret_list def get_wantlist_data(self, wantlist_id): want_items = self.api.get_wantslist_items( self.wantlists[wantlist_id]['idWantsList']).get('item') products = [x for x in want_items if x['type'] == 'product'] metaprod_wants = [x for x in want_items if x['type'] == 'metaproduct'] metaproducts = self.async_get_retry( "metaproducts", [x['idMetaproduct'] for x in metaprod_wants]) product_ids = [prod['idProduct'] for prod in products] for metaprod in metaproducts: for prod in metaprod['product']: product_ids.append(prod['idProduct']) articles = self.async_get_retry("articles", product_ids, **self.config['search_filters']) # Filter down to countries for i in range(len(articles)): for j, item in reversed(list(enumerate(articles[i]['article']))): if item['seller']['address']['country'] not in self.config[ 'search_filters']['countries']: del articles[i]['article'][j] # Output formatting prod_to_metaprod = {} for metaprod in metaproducts: for prod in metaprod['product']: prod_to_metaprod[prod['idProduct']] = prod['idMetaproduct'] lod = [] for ind, prod_id in enumerate(product_ids): seller_prices = { art['seller']['idUser']: art['price'] for art in articles[ind]['article'] } lod.append({"prod_id": prod_id, **seller_prices}) if prod_id in prod_to_metaprod.keys(): lod[-1]['metaprod_id'] = prod_to_metaprod[prod_id] # TODO: Create article_id dataframe (for translation back to article_id list) price_df = pd.DataFrame(lod).set_index(['metaprod_id', 'prod_id']).fillna(np.inf) zero_rows, *_ = np.where((price_df < np.inf).sum(axis=1) == 0) if len(zero_rows) > 0: print( f"There were {len(zero_rows)} cards with 0 sellers matching your search preferences." f"We are removing:") price_df = price_df[~((price_df < np.inf).sum(axis=1) == 0)] return price_df def optimize_wantlist(self, wantlist_id): # TODO Filter items out using wantlist preferences price_df = self.get_wantlist_data(wantlist_id) pass
def __init__(self, config=None): self.api = PyMkmApi(config=config)