Skip to content

Commit 8f9c244

Browse files
committed
Added v0.2.1 code
1 parent 143ea00 commit 8f9c244

File tree

8 files changed

+146
-65
lines changed

8 files changed

+146
-65
lines changed

CHANGELOG.md

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,27 @@
11
# Changelog
22

3+
## V0.2.1; September 1st 2021
4+
5+
Fixing bugs found after release
6+
7+
**Bug fixes**:
8+
9+
- Fixed error on ```sws.youtube._request_path()``` where it would fail if no tkinter display variable is set
10+
- Fixed bug with retrieval of domain records where an unbound variable would exist if the request hung
11+
- Fixed issue where no usage would print when using DNS command without any args
12+
- Fixed issue where no usage would print when using SSL command without any args
13+
- Fixed issue with DNS lookups where on slow connections it would hang waiting for records to load
14+
15+
**Documentation Improvements**:
16+
17+
- Fixed some spelling errors and text duplication
18+
- Improved some of the readme and Usage docs explanations
19+
320
## V0.2.0; September 1st 2021
421

522
Focus for this release was to revamp the package and add a ton of functionality.
623

7-
Features:
24+
**Features**:
825

926
- Simplified and streamlined `redirect.trace()`
1027
- Added Bash autocomplete for ease of use on *nix systems
@@ -14,7 +31,7 @@ Features:
1431
- Added `__main__.py` file for direct cli invocation (`python -m sws`)
1532
- Added logging to existing functions, and all new functions
1633

17-
Documentation Improvements:
34+
**Documentation Improvements**:
1835
- Added additional source, docs, and roadmap links to ```setup.py``` for PyPi
1936
- Added github templates (for issues and PR's), and testing pipeline
2037
- Added testing suite for majority of library functions
@@ -25,7 +42,7 @@ Documentation Improvements:
2542

2643
Initial release went out on github and PyPi. Ported functionality from kuws package.
2744

28-
Features:
45+
**Features**:
2946

3047
- Trace redirects
3148
- Download YouTube videos directly from command line

README.md

Lines changed: 27 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,19 @@
2222

2323
A command line interface, and set of scripts for common web tasks.
2424

25+
## Quick-start
26+
27+
### Installation
28+
29+
#### From PyPi
30+
31+
run ```pip install sws``` or ```sudo pip3 install sws```.
32+
33+
#### From source
34+
35+
1. Clone the github repo ([https://github.com/Descent098/sws](https://github.com/Descent098/sws))
36+
2. cd into the 'sws' root directory (where setup.py is) and run ```pip install .``` or ```sudo pip3 install . ```
37+
2538
## Additional Documentation
2639

2740
API Documentation can be found at [https://kieranwood.ca/sws/](https://kieranwood.ca/sws/)
@@ -30,7 +43,20 @@ User Documentation for the cli can be found at [https://sws.readthedocs.io](http
3043

3144
## What does sws do?
3245

33-
sws is both a cli, and an API with the goal of making common web development tasks simple.
46+
`sws` is both a cli, and an API with the goal of making common web development tasks simple.
47+
48+
Specifically the API is designed to:
49+
50+
1. Be a **cross-platform** utility API
51+
2. Give sensible high-level functions for common tasks
52+
3. Provide useful constants such as a list of dns record types
53+
4. Provide a set of utility classes for common tasks (such as downloads)
54+
55+
The CLI is designed to:
56+
57+
1. Provide a **cross-platform** set of tools
58+
2. Provide a toolbox for ease of use tasks so you don't need to know dozens of commands
59+
3. Make doing simple tasks simpler
3460

3561
## Features & Roadmap
3662

@@ -75,19 +101,6 @@ Really it can be used by anyone, but here are the most typial use cases:
75101
- People learning webdev; Sometimes getting access to tooling while learning webdev can be difficult, this can be a one-stop shop for lots of functionality
76102
- Scripters; people who are looking to use sws functionality in their own projects
77103

78-
## Quick-start
79-
80-
### Installation
81-
82-
#### From PyPi
83-
84-
run ```pip install sws``` or ```sudo pip3 install sws```.
85-
86-
#### From source
87-
88-
1. Clone the github repo ([https://github.com/Descent098/sws](https://github.com/Descent098/sws))
89-
2. cd into the 'sws' root directory (where setup.py is) and run ```pip install .``` or ```sudo pip3 install . ```
90-
91104
## Development-Contribution guide
92105

93106
See [Contribution guide](https://sws.readthedocs.io/contribution-guide/) for details about helping with development.

docs/index.md

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11

2-
32
![sws-banner](./img/sws-banner.png)
43

54
# Welcome to the sws documentation!
@@ -8,6 +7,23 @@
87

98
sws is a utility I wrote with the intention of implementing some common web scripts into one cohesive library. it is primarily intended to be used as a standalone script, but it can also be used as an API.
109

10+
## What does sws do?
11+
12+
`sws` is both a cli, and an API with the goal of making common web development tasks simple.
13+
14+
Specifically the API is designed to:
15+
16+
1. Be a **cross-platform** utility API
17+
2. Give sensible high-level functions for common tasks
18+
3. Provide useful constants such as a list of dns record types
19+
4. Provide a set of utility classes for common tasks (such as downloads)
20+
21+
The CLI is designed to:
22+
23+
1. Provide a **cross-platform** set of tools
24+
2. Provide a toolbox for ease of use tasks so you don't need to know dozens of commands
25+
3. Make doing simple tasks simpler
26+
1127
## Installation
1228

1329
### From PyPi
@@ -21,11 +37,8 @@ run ```pip install sws``` or ```sudo pip3 install sws```.
2137

2238

2339
## Script Usage
24-
You can validate it is installed properly by typing ```sws``` into your terminal, the output should look like this:
2540

26-
Additional details can be found at the documentation available on [https://sws.readthedocs.io/](https://sws.readthedocs.io/).
27-
28-
You can validate it is installed properly by typing ```sws``` into your terminal, the output should look like this:
41+
You can validate if the script is installed properly by typing ```sws``` into your terminal, the output should look like this:
2942

3043
```bash
3144
Super Web Scripts; A command line interface, and set of scripts for web tasks.
@@ -224,4 +237,3 @@ Details on API usage can be found here [https://kieranwood.ca/sws/](https://kier
224237
225238
226239
You can also build local API docs by installing [pdoc3](https://pdoc3.github.io/pdoc/) (```pip install pdoc3``` or ```sudo pip3 install pdoc3```), and then running ```pdoc sws --http localhost:8080```. Go to a browser and type in [http://localhost:8080/sws/utilities/](http://localhost:8080/sws/utilities/)
227-

setup.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
def get_content(*filename:str) -> str:
55
""" Gets the content of a file or files and returns
66
it/them as a string
7+
78
Parameters
89
----------
910
filename : (str)
@@ -24,7 +25,7 @@ def get_content(*filename:str) -> str:
2425

2526
setuptools.setup(
2627
name="sws",
27-
version="0.2.0",
28+
version="0.2.1",
2829
author="Kieran Wood",
2930
author_email="kieran@canadiancoding.ca",
3031
description="An API & command line interface, for common web tasks",

sws/cli.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ def main():
7979
print(f"SSL cert on domain {args['<hostname>']} Expires on: {check_ssl_expiry(args['<hostname>'])}")
8080
if args["--cert"]: # If -c or --cert is specified
8181
pprint(get_ssl_cert(args['<hostname>']))
82+
if not (args["--expiry"] or args["--cert"]):
83+
print(usage)
84+
sys.exit()
8285

8386
elif args["redirects"]: # Begin parsing for redirects subcommand
8487
if args["<ignored>"]:
@@ -94,6 +97,7 @@ def main():
9497

9598
elif args["domains"]: # Begin parsing for ssl subcommand
9699
domain_details = get_domain_info(args["<domain>"])
100+
97101
if args["--expiry"]: # If -e or --expiry is specified
98102
expiry_date = domain_details["expiration_date"]
99103
print(f"Domain {args['<domain>']} set to expire on {expiry_date.strftime('%d-%b-%Y %H:%M:%S')}")
@@ -103,10 +107,16 @@ def main():
103107
else:
104108
print(f"{args['<domain>']} is not registered")
105109
if args["--details"]:
110+
if not domain_details['creation_date']:
111+
print(f"Domain {args['<domain>']} was not registered")
106112
pprint(domain_details)
107113
if args["--available"]:
108114
print(f"Domain {args['<domain>']} is available" if domain_availability(domain_details)[1] else f"{domain_availability(domain_details)[0]}")
109115

116+
if not (args["--expiry"] or args["--registrar"] or args["--details"] or args["--available"]):
117+
print(usage)
118+
sys.exit()
119+
110120
else:
111121
print(usage)
112122
if not os.name == "nt": # Generate bash autocomplete

sws/dns_utilities.py

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,13 +145,17 @@ def get_dns_records(domain:str, as_dict:bool=False) -> Union[List[str], Dict[str
145145
logging.info(f"Stripping http:// protocol from {domain}")
146146
domain = domain.replace("http://", "")
147147

148+
print(f"Beginning dns query to {domain} this may take up to 5 mins depending on connection speed")
148149
if as_dict:
149150
logging.debug("Beginning itteration of record types, and setting up result dictionary")
150151
result = {}
151152
for record_type in RECORD_TYPES:
152153
logging.info(f"Parsing record: {record_type}")
153154
try:
154-
response = dns.resolver.resolve(domain, rdtype=record_type)
155+
try:
156+
response = dns.resolver.resolve(domain, rdtype=record_type, lifetime=4.5)
157+
except dns.exception.Timeout:
158+
... # Record doesn't exist
155159
for record_data in response:
156160
logging.info(f"Parsing record response {record_type}: {record_data.to_text()}")
157161
if record_type == dns.rdatatype.RdataType.HTTPS:
@@ -176,14 +180,17 @@ def get_dns_records(domain:str, as_dict:bool=False) -> Union[List[str], Dict[str
176180
for record_type in RECORD_TYPES:
177181
logging.info(f"Parsing record: {record_type}")
178182
try:
179-
response = dns.resolver.resolve(domain, rdtype=record_type)
183+
try:
184+
response = dns.resolver.resolve(domain, rdtype=record_type, lifetime=4.5)
185+
except dns.exception.Timeout:
186+
... # Record doesn't exist
180187
for record_data in response:
181188
logging.info(f"Parsing record response {record_type}: {record_data.to_text()}")
182189
result.append(f"{record_type.name}: {record_data.to_text()}")
183190
except Exception:
184191
... # Record doesn't exist
185192
if not result:
186-
raise ValueError(f"Domain {domain} did not have any configured records, please check ")
193+
raise ValueError(f"Domain {domain} did not have any configured records, please check spelling")
187194
logging.info(f"Exiting get_dns_records() and returning {result}")
188195
return result
189196

sws/domains.py

Lines changed: 50 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -136,41 +136,58 @@ def get_domain_info(domain: str) -> dict:
136136
# raise e
137137

138138
# Parse response
139-
if not domain_details: # If the domain is not registered
140-
logging.info(f"""Exiting get_domain_info() and returning {{'creation_date': False,
141-
'expiration_date': False,
142-
'last_updated': False,
143-
'name': {domain},
144-
'name_servers': False,
145-
'registrant_cc': False,
146-
'registrar': False}}""")
147-
return {'creation_date': False,
148-
'expiration_date': False,
149-
'last_updated': False,
150-
'name': domain,
151-
'name_servers': False,
152-
'registrant_cc': False,
153-
'registrar': False}
154-
155-
elif domain_details is None: # If the domain is not registered and query completely failed
139+
try:
140+
if domain_details is None: # If the domain is not registered and query completely failed
141+
logging.info(f"""Exiting get_domain_info() and returning {{'creation_date': False,
142+
'expiration_date': False,
143+
'last_updated': False,
144+
'name': {domain},
145+
'name_servers': False,
146+
'registrant_cc': False,
147+
'registrar': False}}""")
148+
return {'creation_date': False,
149+
'expiration_date': False,
150+
'last_updated': False,
151+
'name': domain,
152+
'name_servers': False,
153+
'registrant_cc': False,
154+
'registrar': False}
155+
156+
elif not domain_details: # If the domain is not registered
157+
logging.info(f"""Exiting get_domain_info() and returning {{'creation_date': False,
158+
'expiration_date': False,
159+
'last_updated': False,
160+
'name': {domain},
161+
'name_servers': False,
162+
'registrant_cc': False,
163+
'registrar': False}}""")
164+
return {'creation_date': False,
165+
'expiration_date': False,
166+
'last_updated': False,
167+
'name': domain,
168+
'name_servers': False,
169+
'registrant_cc': False,
170+
'registrar': False}
171+
172+
else: # If there was domain info
173+
logging.info(f"Exiting get_domain_info() and returning {vars(domain_details)}")
174+
return vars(domain_details)
175+
176+
except UnboundLocalError: # When the variable never gets assigned after a failure
156177
logging.info(f"""Exiting get_domain_info() and returning {{'creation_date': False,
157-
'expiration_date': False,
158-
'last_updated': False,
159-
'name': {domain},
160-
'name_servers': False,
161-
'registrant_cc': False,
162-
'registrar': False}}""")
178+
'expiration_date': False,
179+
'last_updated': False,
180+
'name': {domain},
181+
'name_servers': False,
182+
'registrant_cc': False,
183+
'registrar': False}}""")
163184
return {'creation_date': False,
164-
'expiration_date': False,
165-
'last_updated': False,
166-
'name': domain,
167-
'name_servers': False,
168-
'registrant_cc': False,
169-
'registrar': False}
170-
171-
else: # If there was domain info
172-
logging.info(f"Exiting get_domain_info() and returning {vars(domain_details)}")
173-
return vars(domain_details)
185+
'expiration_date': False,
186+
'last_updated': False,
187+
'name': domain,
188+
'name_servers': False,
189+
'registrant_cc': False,
190+
'registrar': False}
174191

175192

176193
def domain_availability(domain_query: dict) -> tuple:

sws/youtube.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,11 +28,15 @@
2828
def _request_path():
2929
"""Prompts user for the link to a youtube video, and path of where to download the video to"""
3030
logging.info("Entering _request_path()")
31-
root = tk.Tk()
32-
root.withdraw()
33-
file_path = str(filedialog.askdirectory(
34-
title="Select Video Output directory",
35-
mustexist=False))
31+
try:
32+
root = tk.Tk()
33+
root.withdraw()
34+
file_path = str(filedialog.askdirectory(
35+
title="Select Video Output directory",
36+
mustexist=False))
37+
except Exception as e:
38+
print(f"Unable to start path selection GUI due to {e}, defualting downloading to current working directory {os.path.abspath('.')}")
39+
file_path = os.path.abspath(".")
3640
return file_path
3741

3842

0 commit comments

Comments
 (0)