diff --git a/CHANGES.txt b/CHANGES.txt index 30e9096..0914104 100644 --- a/CHANGES.txt +++ b/CHANGES.txt @@ -1 +1,45 @@ -v1.0.1, 2018-11-26 -- Initial release. +v1.0.3, 2018-02-08 -- New Release and bug fixes: + +* Fixed path search mechnaism for full Linux support. Fixed #6 +* Fixed pyfileinfo crashing on binary files. Fixed #8 +* Fixed correct time order for [acm]time +* Better terminal color-code comptibility check. Fixed #3 +* Removed ANSI control code garbage for non-ANSI-compatible + terminals often found on Windows (CMD, PowerShell). Fixed #2 +* Implemented a 'uname' check for non-uname supported OS's +* Improved IBM-437 OEM_CHARSET support for block characters. Fixed #5 +* Improved usage text to pip-describe. Fixes #7 +* Improved package location info: [apt,dev,sys,usr] +* Improved pyOSinfo getsitepackages() info +* Improved pipbyday to also show package location +* Clarified table header and made it dynamic for different OS +* Added usage help text to pip-date + +This release fixes all bugs that I could find and track. +But I don't have a Mac so have not been able to test it there. + +Affected files: + + modified: CHANGES.txt + modified: README.md + modified: __init__.py + modified: pip-date + modified: pip-describe + modified: pipbyday + modified: pyOSinfo + modified: pyfileinfo + modified: setup.py + + +v1.0.2, 2018-12-02 -- Package maintenance update with 3 new tools + + * Fix for issue #2 (windows) + * Fixed UI PEP typo + * Added pip-describe (requests) - get full descriptions of not installed packages + * Added pyOSinfo - to get os,platform info + * Added pyfileinfo - to get python-based stat info + * General code and README cleanup + * Updated color-highlight scheme + + +v1.0.1, 2018-11-26 -- Initial release diff --git a/README.md b/README.md index 57902fb..643f59c 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ A simple *Python3* CLI tool to show the installation or modification times of al | STATUS: | Version | Date | Maintained? | |:------- |:------- |:---- |:----------- | -| Working | `1.0.2` | 2018-12-02 | YES | +| Working | `1.0.3` | 2019-02-08 | YES | --- @@ -46,7 +46,7 @@ I also has some functionality of checking packages for outdated and deprecated i But it can do more. Some features are: - Highlight packages with inconsistent file modification times (*mTime*). -- Highlight package **versions** which are not conforming to the [PEM-0440](https://www.python.org/dev/peps/pep-0440/) standard. +- Highlight package **versions** which are not conforming to the [PEP-0440](https://www.python.org/dev/peps/pep-0440/) standard. - Highlight packages installed with an unusual package distribution *priority* given by: **`[chk, src, bin, egg, dev]`** - Highlight *`setuptools`* dependency packages for easy review - Show package installation type: with pip/wheel as **`wheel`**, and source as **`sdist`** (**FIX!**) @@ -81,8 +81,8 @@ and you don't really know what it is going to do. **Q:** *What else is included?* -* A script called **`pip-describe`**, that will do what *pip* doesn't, which is to show -the full text package description from PyPI, for a given *package*. Usually the README. +* A script called **`pip-describe`**, that will do what *pip* doesn't, which is to show the +full-text `long_description` for **any** PyPI package (including those not already installed). * A script called **`pipbyday`**, that will print a simple table with: `mTime/aTime` + `package-name` + `package-version`, sorted by time. @@ -108,7 +108,7 @@ something just send me a PR, or at the very least, a detailed code snippet of wh and what you already have: * [Python3](https://www.python.org/) -* [pip](https://github.com/pypa/pip/). +* [pip](https://github.com/pypa/pip/) ### Installation diff --git a/__init__.py b/__init__.py index 13e948a..2515afa 100644 --- a/__init__.py +++ b/__init__.py @@ -1,2 +1,2 @@ name = "pip-date" -__version__ = "1.0.1" +__version__ = "1.0.3" diff --git a/pip-date b/pip-date index 8ab2564..2b225c4 100755 --- a/pip-date +++ b/pip-date @@ -3,46 +3,88 @@ # -*- coding: utf-8 -*- #---------------------------------------------------------------------- # Author: E:V:A -# Date: 2018-12-01 -# Version: 1.0.2 +# Date: 2018-02-08 +# Version: 1.0.3 # License: GPLv3 # URL: https://github.com/E3V3A/pip-date/ #---------------------------------------------------------------------- # ToDo: -# [ ] better cehck for cTime when using multiple versions: -# usually the first version should be install date... # [/] fix rounding of floats in [a/c/m]Time -# [ ] If using Windows FS, then use cTime, if using *nix FS, use mTime ["platform.architecture()"] -# # [ ] Add CLI options: # - [ ] '-d' : Enable extra debug info # - [ ] '-e' : Show "env" column to display 'virtualenv' name +# - [ ] '-f' : Force to use opposite (to detected) ctime method for FS # - [ ] '-n' : Disable colors # - [ ] '-h' : THIS help/usage message # - [ ] '-v' : THIS program version # - [ ] '-t ' : To highlight packages installed ago # +# NOTES: +# --------------------------------------------------------------------- +# [a/c/m]time +# ------------------------------------------------------------------ +# On Windows (via Cygwin & Python3): +# The creation time is: aTime .CreationTime === .LastAccessTime in Poweshell, but known as "access" time in Linux) +# The modification time is: mTime == cTime .LastWriteTime in Poweshell +# +# On Linux: +# The creation time is: cTime +# The modification time is: mTime +# The access time is: aTime (normally not used) +# +# ==> For seeing last modification time, use "cTime" on Windows FS's, and "mTime" on *linux FS's +# --------------------------------------------------------------------- # References: # [1] https://linuxhandbook.com/file-timestamps/ # [2] https://www.unixtutorial.org/atime-ctime-mtime-in-unix-filesystems/ #---------------------------------------------------------------------- -import re, os, sys, subprocess +import re, os, sys, subprocess, platform import site, pkg_resources from datetime import datetime from datetime import timedelta from time import strftime -__version__ = '1.0.2' +__version__ = '1.0.3' + +#------------------------------------------------ +# OS Check-1 +#------------------------------------------------ +# Apparently for: (Winpython64-3.6.7.0Zero) +# PowerShell/CMD Windows python: TERM=None D:\wimpy\wpy\python-3.6.7.amd64\python.exe -c "import os,sys; print('TERM=%s' % os.getenv('TERM'));" +# PowerShell/CMD Cygwin python: TERM=cygwin C:\cygwin64\bin\python3.6m.exe -c "import os,sys; print('TERM=%s' % os.getenv('TERM'));" +def is_posix(): + px_term = os.getenv("TERM") # [cygwin, xterm, xterm-color, xterm-256color] + px_name = os.name # [posix, nt, ...] + px_plat = sys.platform # [linux, cygwin, win32] + + if ((px_term == "None") or (px_term == "")): # For native Windows "consoles" ofet return "None", since ="". + return False + if (("posix" not in px_name) and ("win32" in px_plat)): + return False + return True + +#------------------------------------------------ +# OS Check-2 +#------------------------------------------------ +# We need to test how [a/c/m]time works on the OS +def isWinFS(): + if platform.architecture()[1] == "WindowsPE": + print("\nUsing cTime for WindowsPE\n") + return True + else: + print("\nUsing mTime for Linux FS\n") + return False #------------------------------------------------ # Text Coloring #------------------------------------------------ # Usage: print (yellow("This is yellow")) def color(text, color_code): - - # Temporary fix for issue #2 - #if (sys.platform == "win32") and not ("xterm" in os.getenv("TERM")): # [xterm, xterm-color, xterm-256color] - # return text + + if not is_posix(): + #if self.nposix: + return text + # for brighter colors, use "1;" in front of "color_code" bright = '' # '1;' return '\x1b[%s%sm%s\x1b[0m' % (bright, color_code, text) @@ -57,18 +99,62 @@ def purple(text): return color(text, 35) # aka. magenta def cyan(text): return color(text, '0;49;96') # 36 def white(text): return color(text, '0;49;97'); # bright white +#------------------------------------------------ +# Print Usage +#------------------------------------------------ +def usage() : + print(" Usage: %s\n" % os.path.basename(__file__)) + print(" This will return a detailed sorted list of all your installed packages.") + print(" The command doesn't take any arguments, and is part of the pip-date") + print(" package. Other commands includeded in this package are: pipbyday,") + print(" pip-describe, pyfileinfo and pyOSinfo.\n") + print(" Please file any bug reports at:") + print(" https://github.com/E3V3A/pip-date/\n") + print(" Version: %s" % __version__) + print(" License: GPLv3\n") + sys.exit(2) + +#------------------------------------------------ +# Print Warning +#------------------------------------------------ +def print_warning(): + print('\n') + print('-'*60) + print(' WARNING!' ) + print(' You are missing out on important color coded information!') + print(' This is because you are probably using a Windows console') + print(' that is not fully supporting ANSI color sequencies.') + print(' For best experience, either run this in Cygwin or WSL,') + print(' or install WinPty, ConEmu or a PowerShell version >6.1.') + print(' If you do have a POSIX compatible color terminal, then') + print(' make sure your TERM environment variable is set.') + #print(' (Usally to \"xterm\".)') + print('-'*60) + #------------------------------------------------ # Print Color Legend #------------------------------------------------ -cc = u'\u2585' # Unicode Character for a "box" (U+2585) +# See: +# https://github.com/PowerShell/PowerShell/issues/8409 +# https://en.wikipedia.org/wiki/Code_page_437 +# https://en.wikipedia.org/wiki/Box-drawing_character +# https://en.wikipedia.org/wiki/Block_Elements +# Let's try: +# 2585, # Look best but is not part of cp437 and thus font dependent & not widely available +# 2580, 25A0, 2588 # IBM-437 +# +#cc = u'\u2585' # Unicode Character for a "5/8th box" # (U+2585) is not part of IBM-437 +#cc = u'\u2588' # Unicode Character for a "full box" # (U+2588) is part of IBM-437 +#cc = u'\u25A0' # Unicode Character for a "black square" # (U+25A0) is part of IBM-437 +cc = u'\u2580' # Unicode Character for a "Upper half block" # (U+2580) is part of IBM-437 + def print_legend(): print( " {} = ERROR (preventing package processing)".format(red(cc)) ) - print( " {} = Bad / Non-Standard Installation Path".format(purple(cc)) ) + print( " {} = Using a Bad, Deprecated or Non-Standard installation Path".format(purple(cc)) ) print( " {} = Possibly Multiple installations (differing file times)".format(yellow(cc)) ) print( " {} = Recently Changed / Installed (in last 7 days)".format(cyan(cc)) ) print( " {} = Non-PEM-compliant Version string (PEP-0440) | ~/.local install".format(green(cc)) ) print( " {} = A 'setuptools' dependency package".format(blue(cc)) ) - #print( " {} = ERROR".format(white(cc)) ) #------------------------------------------------ # Helper Functions @@ -87,18 +173,27 @@ def to_filename(name): return name.replace('-', '_') def test_loc(loc): + # Test package location to give us some idea of what type of install it came with. + # .local : are usually local user installs in: $HOME/.local/lib/pythonX.Y/site-packages/... + # site-packages : are usually system user installs (sudo) + # dist-packages : are usually system package-manager installs (apt) + # /PATH/ : are usually developer installs using "pip install ." if '.local' in loc: - ploc = bgreen('usr') # user + ploc = bgreen('usr') # user (unprivileged local install) + elif 'dist-packages' in loc: + ploc = 'apt' # system (apt package-manger installed) elif 'site-packages' in loc: - ploc = 'sys' # system + ploc = 'sys' # system (user sudo installed) else: - ploc = red('???') + #ploc = red(loc) # show actual path + ploc = red('dev') # dev (user development install via "pip install .") return ploc def pre2txt(pre): # Distribution "precedence" constants: (../pkg_resources/__init__.py) # EGG_DIST, BINARY_DIST, SOURCE_DIST, CHECKOUT_DIST, DEVELOP_DIST : [3,2,1,0,-1] # { 'egg': 3, 'bin': 2, 'src': 1, 'chk': 0, 'dev': -1 } + # However, this seem poorly implemented since most packages show "-1" or 3. d = ['chk', 'src', 'bin', 'egg', 'dev'] return d[pre] @@ -115,6 +210,9 @@ def pkgcol(pkgarr): cygset = ['setuptools', 'appdirs', 'packaging', 'pyparsing', 'six' ] # Cygwin python3-setuptools dependency packages #cygset += ['wheel', 'virtualenv', 'pipenv', 'pip'] # ...some additional essentials #cygset += ['scikit-build', 'distlib'] # ...some additional essentials + # NOTE! + # We can't use "pip" because the we're only checking if the string is present in line, + # Thus anything with "pip" in it would be caught, so we need a smarter RE here. line = '' for i in range(len(pkgarr)): @@ -134,67 +232,133 @@ def pkgcol(pkgarr): #------------------------------------------------ print() debug = 0 +#nposix = 0 pcnt = 0 pkg = [] -site_loc = site.getsitepackages()[0] + +#------------------ +# CLI arguments +#------------------ +narg = len(sys.argv) - 1 +if narg >= 1: + #pkg = sys.argv[1] + usage() +#if is_posix(): +# nposix = 1 +#------------------ + +# Check [a/c,m]time availability +useWinStat = False # Linux ELF based FS system +if isWinFS(): + useWinStat = True # WindowsPE FS system + +# MacOS: ?? +# Cygwin: native python, we only have 1 location: +# /usr/lib/python3.6/site-packages +# Linux Mint (19.1): we have several (3) +# /usr/local/lib/python3.6/dist-packages +# /usr/lib/python3/dist-packages +# /usr/lib/python3.6/dist-packages +# Also add the unprivileged user's local package location: +# $HOME/.local/lib/python3.6/site-packages/ +site_loc = site.getsitepackages() # [...] +if debug: print("site_locs (site): ", site_loc) +site_loc += [site.getusersitepackages()] # add $HOME/.local/lib/python3.6/site-packages/ +if debug: print("site_locs (all): ", site_loc) + for d in pkg_resources.working_set : + try: pkg_name = d.project_name # pkg_ver = d.version # - pkg_loc = d.location # + #pkg_loc = d.location # NOT always a file! pkg_typ = 'n/a' #"wheel" if d.location.is_wheel else "sdist" # 'Type' - pkg_pre = pre2txt(d.precedence) if d.precedence != -1 else '' # 'Prec' + + if debug: + pkg_pre = d.precedence # 'Prec' [-1..3] + else: + pkg_pre = pre2txt(d.precedence) if (d.precedence != -1) else '' # 'Prec' string + pkg_ins = d.get_metadata('INSTALLER').strip() if d.has_metadata('INSTALLER') else '' # get_metadata_lines() '???' pkg_whl = d.get_metadata('WHEEL').strip() if d.has_metadata('WHEEL') else '' # get_metadata_lines() '???' + # ^^^^^ This often have multiple lines, we need to format: + if pkg_whl : + pw = pkg_whl.split('\n') + pw = '\n ' +'\n '.join(pw,) + pkg_whl = pw except ValueError as e: print( red("ERROR:") + " %s" % e) + #---------------------------------- + # Get the correct package location + #---------------------------------- + # Because d.location doesn't return a file, but only a directory, + # for certain packages, we also check the "module directory" ??? + try: + mod_dir = next(d._get_metadata('top_level.txt')) # module_dir + pkg_loc = os.path.join(d.location, mod_dir) # + os.stat(pkg_loc) # + + except (StopIteration, OSError): + try: + pkg_loc = os.path.join(d.location, d.key) + os.stat(pkg_loc) + except: + pkg_loc = d.location + #---------------------------------- + if debug : - print("pkg_loc: %s: %s (%s)" % (pkg_name.ljust(20,' '), pkg_loc, pkg_pre) ) + print('-'*40) + print("pkg_loc: %s: %s (%s)" % (pkg_name.ljust(20,' '), pkg_loc, pkg_pre) ) # pkg_pre always empty ?? print("pkg_typ: %s" % pkg_ins) print("pkg_whl: %s" % pkg_whl) print("pkg_ins: %s" % pkg_ins) + # A work-around for packages with deprecated location(s): + if ".egg" in pkg_loc: + print( purple("Found Bad Path Location for:") + " %s" % white(pkg_name)) + print( "Package Location found at: %s" % (pkg_loc)); + #---------------------------------- - # Testing Package Locations + # Getting OS Dependent TimeStamps #---------------------------------- - # A workaround for packages with bad Location: - if ".egg" in pkg_loc: - print( purple("Found Bad Path Location for:") + " %s" % white(pkg_name)) - print("Package Location set to: %s" % (pkg_loc)); - pkg_loc = site_loc - - # /usr/lib/python3.6/site-packages/pyflightdata-0.5.6.dist-info/ - # Wheel uses .dist-info directories; egg uses .egg-info. - pkg_path = pkg_loc + "/" + to_filename(pkg_name) + "-" + to_filename(pkg_ver) - pkg_loc1 = pkg_path + ".dist-info" - pkg_loc2 = pkg_path + "-py3.6.egg-info" - pkg_loc3 = pkg_path + "-py3.6.egg" - # any others? - - if os.path.exists(pkg_loc1): - tsc = os.path.getctime(pkg_loc1) - tsm = os.path.getmtime(pkg_loc1) - elif os.path.exists(pkg_loc2): - tsc = os.path.getctime(pkg_loc2) - tsm = os.path.getmtime(pkg_loc2) - elif os.path.exists(pkg_loc3): - tsc = os.path.getctime(pkg_loc3) - tsm = os.path.getmtime(pkg_loc3) - else: + # NOTE: + # (1) [acm]time as used in variable names HERE, is true for LinuxFS, + # but swapped for WindowsFS's + # (2) In a WindowsPE based FS: + # (a) The true "creation" time is the (python stat) "atime" + # (b) The true "modification" time is the (python stat) "mtime"=="ctime" + # (3) In a ELF based LinuxFS: + # aTime = access time ... - Rarely used because of FS performance + # mtime = modification time - + # ctime = creation time - is the "real" last modification time on windows + + + if debug: print("pkg_loc: %s" % pkg_loc) + if os.path.exists(pkg_loc): + if useWinStat: + tsc = os.path.getctime(pkg_loc) # swap! WindowsFS: "creation" time is "atime" + tsm = os.path.getatime(pkg_loc) # swap! WindowsFS: "modification" time is "mtime" + else: + tsc = os.path.getctime(pkg_loc) # LinuxFS (ctime) + tsm = os.path.getmtime(pkg_loc) # LinuxFS (mtime) + else: print(red("Skipping Bad Path of:") + " %s: \t%s" % (pkg_name, pkg_path)) # to_filename(pkg_name)) continue - + #---------------------------------- # Processing Time Stamps #---------------------------------- - pkg_ctime = datetime.fromtimestamp(tsc).strftime("%Y-%m-%d %H:%M:%S").strip() - pkg_mtime = datetime.fromtimestamp(tsm).strftime("%Y-%m-%d %H:%M:%S").strip() + pkg_ctime = datetime.fromtimestamp(tsc).strftime("%Y-%m-%d %H:%M:%S").strip() # str + pkg_mtime = datetime.fromtimestamp(tsm).strftime("%Y-%m-%d %H:%M:%S").strip() # str # NOTE: If TS differs by < 1 second, it will not show. To do so, test: tsc == tsm - if pkg_ctime != pkg_mtime: + max_tdelta = 60 # Max allowed time difference: ~60s + tdelta = abs(tsc - tsm) # Calculate time difference + #if pkg_ctime != pkg_mtime: # This is too restrictive (OS need seconds to install) + if tdelta > max_tdelta: # pkg_mtime = yellow(pkg_mtime) else: pkg_mtime = '' @@ -207,7 +371,7 @@ for d in pkg_resources.working_set : #---------------------------------- if pkg_pre: - pkg_pre = yellow(pkg_pre) + " " # + pkg_pre = yellow(pkg_pre) + " " # [egg,...] if not is_canonical(pkg_ver): pkg_ver = green(pkg_ver) + " "*3 # green + ugly color-code-length hack when using colors... @@ -223,9 +387,13 @@ for d in pkg_resources.working_set : pcnt += 1 pkg += ["{:20} {:<20} {:<20} {:<16} {:6} {:<4} {:5} {:3}".format(pkg_name.ljust(20,' '),pkg_ctime,pkg_mtime,pkg_ver,pkg_ins,pkg_pre,pkg_typ,pkg_loc) ] -header_str = "{:20} {:20} {:20} {:16} {:6} {:4} {:5} {:3}".format('Package'.ljust(20, ' '), 'Installed (cTime)', 'Modified (mTime)', 'Version', 'Inst', 'Prec', 'Type ', 'Loc') -hlen = len(header_str) +if useWinStat: +# header_str = "{:20} {:20} {:20} {:16} {:6} {:4} {:5} {:3}".format('Package'.ljust(20, ' '), 'Installed (cTime)', 'Modified (mTime)', 'Version', 'Inst', 'Prec', 'Type ', 'Loc') + header_str = "{:20} {:20} {:20} {:16} {:6} {:4} {:5} {:3}".format('Package'.ljust(20, ' '), 'LastModified (mTime)', 'FirstSeen (aTime)', 'Version', 'Inst', 'Prec', 'Type ', 'Loc') +else: + header_str = "{:20} {:20} {:20} {:16} {:6} {:4} {:5} {:3}".format('Package'.ljust(20, ' '), 'LastModified (mTime)', 'FirstSeen (cTime)', 'Version', 'Inst', 'Prec', 'Type ', 'Loc') +hlen = len(header_str) print('\n' + header_str) print("-"*hlen) @@ -238,6 +406,11 @@ print_legend() print("-"*hlen) print("Found %d packages." % pcnt) + +#if not nposix: +if not is_posix(): + print_warning() + print("\nDone!") sys.exit(0) diff --git a/pip-describe b/pip-describe index 4004fe5..50cfaa4 100755 --- a/pip-describe +++ b/pip-describe @@ -4,8 +4,8 @@ #---------------------------------------------------------------------- # File Name : pip-describe # Author : E:V:A -# Last Modified : 2018-12-01 -# Version : 1.0.0 +# Last Modified : 2018-02-08 +# Version : 1.0.1 # License : GPLv3 # URL : https://github.com/E3V3A/pip-date #---------------------------------------------------------------------- @@ -13,21 +13,22 @@ # from the `pip search` results. # [ ] But we can always add CLI switch `-s` for summary #---------------------------------------------------------------------- -import sys +import os, sys #import requests as req try: import requests as req -except ModuleNotFoundError as err: +# exception ImportError as err: # 3.3 +except ModuleNotFoundError as err: # 3.6 print("\nThis program need the \"requests\" package to work.") print("Please download and install from:\nhttps://github.com/requests/requests") print(err) sys.exit(1) -__version__ = '1.0.0' +__version__ = '1.0.1' def usage() : - print("\n Usage: %s \n" % sys.argv[0]) + print("\n Usage: %s \n" % os.path.basename(__file__)) # sys.argv[0] print(" This will return the full-text package description (usually the README)") print(" as found on PyPI, for any given .\n") print(" This script is part of the pip-date package at:") @@ -53,3 +54,5 @@ if res.status_code == 200: else: print('\nERROR (%s): Package \"%s\" doesn\'t exist!' % (res.status_code,pkg)) sys.exit(2) + +sys.exit(0) diff --git a/pipbyday b/pipbyday index 91b2834..046ff8a 100755 --- a/pipbyday +++ b/pipbyday @@ -1,6 +1,16 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -# Prints when python packages were installed +# pipbyday- Prints when python packages were installed +#---------------------------------------------------------------------- +# File Name : pipbyday +# Author : E:V:A +# Last Modified : 2018-02-08 +# Version : 1.0.1 +# License : GPLv3 +# URL : https://github.com/E3V3A/pip-date +# Description : Print a sorted list when python packages were installed +# : This is based on mtime or ctime, depending on OS +#---------------------------------------------------------------------- from __future__ import print_function from datetime import datetime @@ -8,15 +18,17 @@ import os, platform import pkg_resources as p from time import strftime +__version__ = '1.0.1' + if __name__ == "__main__": packages = [] if platform.architecture()[1] == "WindowsPE": isWinFS = True - print("\nUsing ctime for WindowsPE") + print("\nUsing ctime for WindowsPE\n") else: isWinFS = False - print("\nUsing mtime for Linux FS") + print("\nUsing mtime for Linux FS\n") # The package: "name version" for package in p.working_set: @@ -43,9 +55,12 @@ if __name__ == "__main__": mtime = os.path.getmtime(pkg_loc) # modification time on Linux mtime = datetime.fromtimestamp(mtime).strftime("%Y-%m-%d %H:%M:%S") - packages.append([mtime, pkg_nam_ver]) + #packages.append([mtime, pkg_nam_ver]) + packages.append([mtime, pkg_nam_ver, pkg_loc]) - for mtime, pkg_nam_ver in sorted(packages): - print("{:22} : {:<30}".format(mtime.ljust(22,' '), pkg_nam_ver)) + for mtime, pkg_nam_ver, pkg_loc in sorted(packages): + print("{:22} : {:<30} : {:<40}".format(mtime.ljust(22,' '), pkg_nam_ver, pkg_loc)) + #for mtime, pkg_nam_ver in sorted(packages): + # print("{:22} : {:<30}".format(mtime.ljust(22,' '), pkg_nam_ver)) print("\nDone!") diff --git a/pyOSinfo b/pyOSinfo index e53e354..a3d8e39 100755 --- a/pyOSinfo +++ b/pyOSinfo @@ -4,8 +4,8 @@ #---------------------------------------------------------------------- # File Name : pyOSinfo # Author : E:V:A -# Last Modified : 2018-12-01 -# Version : 1.0.0 +# Last Modified : 2018-02-08 +# Version : 1.0.1 # License : GPLv3 # URL : https://github.com/E3V3A/pip-date/ # Description : Show some system, os and platform information as seen by python3 @@ -13,10 +13,17 @@ import os, sys, platform, site from os.path import join -__version__ = '1.0.0' +__version__ = '1.0.1' TRUECOLOR = "\x1b[38;2;255;100;0mTRUECOLOR\x1b[0m" +def hasUname(): + try: + os.uname()[0] + return True + except: + return False + print("\nCurrent OS variables as seen by Python3 (%s)\n" % platform.python_version() ) print('os.getenv(\"TERM\"): %s' % os.getenv("TERM")) # [xterm, xterm-color, xterm-256color] print('os.name: %s' % os.name ) # [posix, nt, java] @@ -24,12 +31,17 @@ print('os.sys.platform: %s' % os.sys.platform ) # [linux, win32, cygwin print('sys.platform: %s' % sys.platform ) # [linux, win32, cygwin, darwin] print('TRUECOLOR (orange): %s' % TRUECOLOR ) # TRUECOLOR written in nice orange +# Apparently some Windows Pythons doesn't provide os.uname attribute. +# Like: Winpython64-3.6.7.0Zero print('\nos.uname:') # sysname, nodename, release, version, machine -print('\tnodename: %s' % os.uname()[1] ) # -print('\tmachine: %s' % os.uname()[4] ) # -print('\tsysname: %s' % os.uname()[0] ) # -print('\trelease: %s' % os.uname()[2] ) # -print('\tversion: %s' % os.uname()[3] ) # +if hasUname(): + print('\tnodename: %s' % os.uname()[1] ) # + print('\tmachine: %s' % os.uname()[4] ) # + print('\tsysname: %s' % os.uname()[0] ) # + print('\trelease: %s' % os.uname()[2] ) # + print('\tversion: %s' % os.uname()[3] ) # +else: + print('\tN/A' ) print('\nplatform:') print('\tnode: %s' % platform.node() ) @@ -44,8 +56,12 @@ print('\tarchitecture (2): (%s,%s)' % platform.architecture() ) # (b #print('\twin32_ver (4): (%s,%s,%s,%s)' % platform.win32_ver() ) # (release, version, csd, ptype) print("\nsite:") -print("\tgetsitepackages[0]: %s" % site.getsitepackages()[0]) -print("\tPREFIXES (2): %s" % site.PREFIXES) +print("\tgetusersitepackages: %s" % site.getusersitepackages()) +i=0 +for ploc in site.getsitepackages(): # Returns a [] + print("\tgetsitepackages[%i]: %s" % (i, ploc)) # site.getsitepackages()[0]) + i+=1 +print("\n\tPREFIXES (2): %s" % site.PREFIXES) print("\tUSER_SITE: %s" % site.USER_SITE) print("\tUSER_BASE: %s" % site.USER_BASE) diff --git a/pyfileinfo b/pyfileinfo index 93b3523..b1f81b7 100755 --- a/pyfileinfo +++ b/pyfileinfo @@ -4,8 +4,8 @@ #---------------------------------------------------------------------- # File Name : pyfileinfo # Author : E:V:A -# Last Modified : 2018-12-01 -# Version : 1.1.0 +# Last Modified : 2018-02-08 +# Version : 1.1.1 # License : GPLv3 # URL : https://github.com/E3V3A/pip-date # Description : Show detailed file information for a given file using python's os.stat info @@ -17,13 +17,13 @@ import os, sys, stat, platform import time, getopt -__version__ = '1.1.0' +__version__ = '1.1.1' #------------------------------------------------ # Helper Functions #------------------------------------------------ def usage() : - print("\nUsage: %s " % sys.argv[0]) + print("\nUsage: %s " % os.path.basename(__file__)) print("\nOptions:") print(" -c : For License/Copyright info") print(" -h, --help : For this help ") @@ -90,11 +90,17 @@ except IsADirectoryError as e: sys.exit(2) count = 0 -for lines in fhand: - count = count + 1 - -fdata = open(filename).read() -t_char = len(fdata) +is_binary = False +try: + for lines in fhand: + count = count + 1 + fdata = open(filename).read() + t_char = len(fdata) +except UnicodeDecodeError as e: + #print ("\nThis is a binary file.") + is_binary = True + t_char = 0 + pass try: file_stats = os.stat(filename) @@ -117,7 +123,15 @@ file_info = { } print (" File Name : ", file_info['fname']) -print (" File Type : ", "directory" if stat.S_ISDIR(file_stats[stat.ST_MODE]) else "\"normal\" file") +print (" File Type : ", end='') +if (stat.S_ISDIR(file_stats[stat.ST_MODE])): + print (" directory") + #sys.exit(2) +elif is_binary: + print (" binary") +else: + print(" normal (text) file") + print (" File Size : ", file_info['fsize'] , " (bytes)") print (" Total Lines : ", file_info['no_of_lines']) print (" Total Chars : ", file_info['t_char']) diff --git a/setup.py b/setup.py index 4704d36..8a43890 100644 --- a/setup.py +++ b/setup.py @@ -18,7 +18,7 @@ def readme(): setup( name = 'pip-date', - version = '1.0.2', + version = '1.0.3', author = 'E:V:A', author_email = 'xdae3v3a@gmail.com', description = 'Show the installation/modification times of all your pip packages and other tools', @@ -27,7 +27,7 @@ def readme(): #long_description = readme(), #long_description_content_type = 'text/markdown', license='LICENSE.txt', - url = 'https://github.com/e3v3a/pip-date/', + url = 'https://github.com/E3V3A/pip-date/', packages = find_packages(), scripts=['pip-date', 'pip-describe', 'pipbyday', 'pyfileinfo', 'pyOSinfo'], keywords = 'pip date package management setuptools wheel egg stat os', @@ -42,12 +42,13 @@ def readme(): 'Operating System :: OS Independent', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', 'Topic :: Software Development :: Version Control', 'Topic :: System :: Software Distribution', 'Topic :: System :: Installation/Setup', ], project_urls={ - 'Bug Reports': 'https://github.com/e3v3a/pip-date/issues', + 'Bug Reports': 'https://github.com/E3V3A/pip-date/issues', #'Funding' : 'https://donate.pypi.org', #'Credits' : 'http://saythanks.io/to/example', #'Source' : 'https://github.com/pypa/sampleproject/',