Coverage for amazonorders/cli.py: 81.15%
122 statements
« prev ^ index » next coverage.py v7.4.0, created at 2024-01-24 18:41 +0000
« prev ^ index » next coverage.py v7.4.0, created at 2024-01-24 18:41 +0000
1import datetime
2import logging
3from typing import Any
5import click
6from click.core import Context
8from amazonorders.conf import DEFAULT_OUTPUT_DIR
9from amazonorders.exception import AmazonOrdersError
10from amazonorders.orders import AmazonOrders
11from amazonorders.session import AmazonSession, IODefault
13__author__ = "Alex Laird"
14__copyright__ = "Copyright 2024, Alex Laird"
15__version__ = "1.0.4"
17logger = logging.getLogger("amazonorders")
20class IOClick(IODefault):
21 def echo(self,
22 msg,
23 fg=None,
24 **kwargs):
25 click.secho(msg, fg=fg)
27 def prompt(self,
28 msg,
29 type=None,
30 **kwargs):
31 return click.prompt(msg, type=type)
34@click.group()
35@click.option('--username', help="An Amazon username.")
36@click.option('--password', help="An Amazon password.")
37@click.option('--debug', is_flag=True, default=False, help="Enable debugging and send output to command line.")
38@click.option('--max-auth-attempts', default=10,
39 help="Will continue in the login auth loop this many times (successes and failures).")
40@click.option('--output-dir', default=DEFAULT_OUTPUT_DIR,
41 help="The directory where any output files should be produced.")
42@click.pass_context
43def amazon_orders_cli(ctx,
44 **kwargs: Any):
45 """
46 amazon-orders is an unofficial library that provides a command line interface alongside a programmatic API that
47 can be used to interact with Amazon.com's consumer-facing website.
49 This works by parsing website data from Amazon.com. A nightly build validates functionality to ensure its
50 stability, but as Amazon provides no official API to use, this package may break at any time. This
51 package only supports the English version of the website.
53 Documentation can be found at https://amazon-orders.readthedocs.io.
55 Session data is persisted between requests and interactions with the CLI, minimizing the need to reauthenticate
56 after a successful login attempt.
57 """
58 _print_banner()
60 ctx.ensure_object(dict)
61 for key, value in kwargs.items():
62 if value:
63 ctx.obj[key] = value
65 if kwargs["debug"]:
66 logger.setLevel(logging.DEBUG)
67 logger.addHandler(logging.StreamHandler())
69 username = kwargs.get("username")
70 password = kwargs.get("password")
72 amazon_session = AmazonSession(username,
73 password,
74 debug=kwargs["debug"],
75 io=IOClick(),
76 max_auth_attempts=kwargs["max_auth_attempts"],
77 output_dir=kwargs["output_dir"])
79 if amazon_session.auth_cookies_stored():
80 if username or password:
81 click.echo("Info: You've provided --username and --password, but because a previous session still exists,"
82 "that is being ignored. If you would like to reauthenticate, call the `logout` command first.\n")
83 elif not username and not password:
84 click.echo(ctx.get_help())
86 ctx.fail("Amazon --username and --password must be provided, since no previous session was found.")
88 ctx.obj["amazon_session"] = amazon_session
91@amazon_orders_cli.command()
92@click.pass_context
93@click.option('--year', default=datetime.date.today().year,
94 help="The year for which to get order history, defaults to the current year.")
95@click.option('--start-index', help="Retrieve the single page of history at the given index.")
96@click.option('--full-details', is_flag=True, default=False,
97 help="Retrieve the full details for each order in the history.")
98def history(ctx: Context,
99 **kwargs: Any):
100 """
101 Retrieve Amazon order history for a given year.
102 """
103 amazon_session = ctx.obj["amazon_session"]
105 year = kwargs["year"]
106 start_index = kwargs["start_index"]
107 full_details = kwargs["full_details"]
109 click.echo("""-----------------------------------------------------------------------
110Order History for {}{}{}
111-----------------------------------------------------------------------\n""".format(year,
112 ", startIndex={}, one page".format(
113 start_index) if start_index else ", all pages",
114 ", with full details" if full_details else ""))
116 click.echo("Info: This might take a minute ...\n")
118 try:
119 amazon_session.login()
121 amazon_orders = AmazonOrders(amazon_session,
122 debug=amazon_session.debug,
123 output_dir=ctx.obj["output_dir"])
125 orders = amazon_orders.get_order_history(year=kwargs["year"],
126 start_index=kwargs["start_index"],
127 full_details=kwargs["full_details"], )
129 for order in orders:
130 click.echo("{}\n".format(_order_output(order)))
131 except AmazonOrdersError as e:
132 logger.debug("An error occurred.", exc_info=True)
133 ctx.fail(str(e))
136@amazon_orders_cli.command()
137@click.pass_context
138@click.argument("order_id")
139def order(ctx: Context,
140 order_id: str):
141 """
142 Retrieve the full details for the given Amazon order ID.
143 """
144 amazon_session = ctx.obj["amazon_session"]
146 try:
147 amazon_session.login()
149 amazon_orders = AmazonOrders(amazon_session,
150 debug=amazon_session.debug,
151 output_dir=ctx.obj["output_dir"])
153 order = amazon_orders.get_order(order_id)
155 click.echo("{}\n".format(_order_output(order)))
156 except AmazonOrdersError as e:
157 logger.debug("An error occurred.", exc_info=True)
158 ctx.fail(str(e))
161@amazon_orders_cli.command(short_help="Check if persisted session exists.")
162@click.pass_context
163def check_session(ctx: Context):
164 """
165 Check if a persisted session exists, meaning commands can be called without needing to provide credentials.
166 """
167 amazon_session = ctx.obj["amazon_session"]
168 if amazon_session.auth_cookies_stored():
169 click.echo("Info: A persisted session exists.\n")
170 else:
171 click.echo("Info: No persisted session exists.\n")
174@amazon_orders_cli.command()
175@click.pass_context
176def logout(ctx: Context):
177 """
178 Logout of existing Amazon sessions and clear cookies.
179 """
180 amazon_session = ctx.obj["amazon_session"]
181 amazon_session.logout()
183 click.echo("Info: Successfully logged out of the Amazon session.\n")
186def _print_banner():
187 click.echo("""
188=======================================================================
189 ___ _____ _
190 / _ \ | _ | | |
191/ /_\ \_ __ ___ __ _ _______ _ __ | | | |_ __ __| | ___ _ __ ___
192| _ | '_ ` _ \ / _` |_ / _ \| '_ \ | | | | '__/ _` |/ _ \ '__/ __|
193| | | | | | | | | (_| |/ / (_) | | | | \ \_/ / | | (_| | __/ | \__ \\
194\_| |_/_| |_| |_|\__,_/___\___/|_| |_| \___/|_| \__,_|\___|_| |___/
195=======================================================================\n""")
198def _order_output(order):
199 order_str = """-----------------------------------------------------------------------
200Order #{}
201-----------------------------------------------------------------------""".format(order.order_number)
203 order_str += "\n Shipments: {}".format(order.shipments)
204 order_str += "\n Order Details Link: {}".format(order.order_details_link)
205 order_str += "\n Grand Total: ${:,.2f}".format(order.grand_total)
206 order_str += "\n Order Placed Date: {}".format(order.order_placed_date)
207 order_str += "\n {}".format(order.recipient)
208 if order.payment_method:
209 order_str += "\n Payment Method: {}".format(order.payment_method)
210 if order.payment_method_last_4:
211 order_str += "\n Payment Method Last 4: {}".format(order.payment_method_last_4)
212 if order.subtotal:
213 order_str += "\n Subtotal: ${:,.2f}".format(order.subtotal)
214 if order.shipping_total:
215 order_str += "\n Shipping Total: ${:,.2f}".format(order.shipping_total)
216 if order.subscription_discount:
217 order_str += "\n Subscription Discount: ${:,.2f}".format(order.subscription_discount)
218 if order.total_before_tax:
219 order_str += "\n Total Before Tax: ${:,.2f}".format(order.total_before_tax)
220 if order.estimated_tax:
221 order_str += "\n Estimated Tax: ${:,.2f}".format(order.estimated_tax)
222 if order.refund_total:
223 order_str += "\n Refund Total: ${:,.2f}".format(order.refund_total)
224 if order.order_shipped_date:
225 order_str += "\n Order Shipped Date: {}".format(order.order_shipped_date)
226 if order.refund_completed_date:
227 order_str += "\n Refund Completed Date: {}".format(order.refund_completed_date)
229 order_str += "\n-----------------------------------------------------------------------"
231 return order_str
234if __name__ == "__main__":
235 amazon_orders_cli(obj={})