Coverage for amazonorders/cli.py: 80.95%
126 statements
« prev ^ index » next coverage.py v7.4.0, created at 2024-01-25 22:50 +0000
« prev ^ index » next coverage.py v7.4.0, created at 2024-01-25 22:50 +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.6"
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")
186@amazon_orders_cli.command()
187@click.pass_context
188def version(ctx: Context):
189 """
190 Get the package version.
191 """
192 click.echo("Version: {}\n".format(__version__))
195def _print_banner():
196 click.echo("""
197=======================================================================
198 ___ _____ _
199 / _ \ | _ | | |
200/ /_\ \_ __ ___ __ _ _______ _ __ | | | |_ __ __| | ___ _ __ ___
201| _ | '_ ` _ \ / _` |_ / _ \| '_ \ | | | | '__/ _` |/ _ \ '__/ __|
202| | | | | | | | | (_| |/ / (_) | | | | \ \_/ / | | (_| | __/ | \__ \\
203\_| |_/_| |_| |_|\__,_/___\___/|_| |_| \___/|_| \__,_|\___|_| |___/
204=======================================================================\n""")
207def _order_output(order):
208 order_str = """-----------------------------------------------------------------------
209Order #{}
210-----------------------------------------------------------------------""".format(order.order_number)
212 order_str += "\n Shipments: {}".format(order.shipments)
213 order_str += "\n Order Details Link: {}".format(order.order_details_link)
214 order_str += "\n Grand Total: ${:,.2f}".format(order.grand_total)
215 order_str += "\n Order Placed Date: {}".format(order.order_placed_date)
216 order_str += "\n {}".format(order.recipient)
217 if order.payment_method:
218 order_str += "\n Payment Method: {}".format(order.payment_method)
219 if order.payment_method_last_4:
220 order_str += "\n Payment Method Last 4: {}".format(order.payment_method_last_4)
221 if order.subtotal:
222 order_str += "\n Subtotal: ${:,.2f}".format(order.subtotal)
223 if order.shipping_total:
224 order_str += "\n Shipping Total: ${:,.2f}".format(order.shipping_total)
225 if order.subscription_discount:
226 order_str += "\n Subscription Discount: ${:,.2f}".format(order.subscription_discount)
227 if order.total_before_tax:
228 order_str += "\n Total Before Tax: ${:,.2f}".format(order.total_before_tax)
229 if order.estimated_tax:
230 order_str += "\n Estimated Tax: ${:,.2f}".format(order.estimated_tax)
231 if order.refund_total:
232 order_str += "\n Refund Total: ${:,.2f}".format(order.refund_total)
233 if order.order_shipped_date:
234 order_str += "\n Order Shipped Date: {}".format(order.order_shipped_date)
235 if order.refund_completed_date:
236 order_str += "\n Refund Completed Date: {}".format(order.refund_completed_date)
238 order_str += "\n-----------------------------------------------------------------------"
240 return order_str
243if __name__ == "__main__":
244 amazon_orders_cli(obj={})