diff --git a/.gitignore b/.gitignore index 091919c..83ed8e8 100644 --- a/.gitignore +++ b/.gitignore @@ -63,6 +63,11 @@ instance/ # Sphinx documentation docs/_build/ +# py.test +.cache/* +.pytest_cache/* +.pytest_config + # PyBuilder target/ diff --git a/Dockerfile b/Dockerfile index 3514060..5eddc8c 100755 --- a/Dockerfile +++ b/Dockerfile @@ -1,55 +1,46 @@ # TensorPy Docker Image -FROM ubuntu:15.10 +FROM ubuntu:17.10 -#======================================= -# Install Python and Basic Python Tools -#======================================= -RUN apt-get update && apt-get install -y python python-pip python-setuptools \ - python-dev python-distribute python-virtualenv +#================================ +# Update apt-get package sources +#================================ +RUN apt-get update -#========================================= -# Install Bash Command Line Tools and Git -#========================================= +#================================================== +# Install Bash Command Line Tools, Python, and Git +#================================================== RUN apt-get -qy --no-install-recommends install \ + python \ + python-dev \ + python-pip \ + python-distribute \ + python-virtualenv \ + python-setuptools \ sudo \ unzip \ wget \ curl \ + libxi6 \ + libgconf-2-4 \ vim \ git-core \ && rm -rf /var/lib/apt/lists/* -#======================================== -# Add normal user with passwordless sudo -#======================================== -RUN sudo useradd seluser --shell /bin/bash --create-home \ - && sudo usermod -a -G sudo seluser \ - && echo 'ALL ALL = (ALL) NOPASSWD: ALL' >> /etc/sudoers - -#============================== -# Locale and encoding settings -#============================== -ENV LANGUAGE en_US.UTF-8 -ENV LANG ${LANGUAGE} -RUN locale-gen ${LANGUAGE} \ - && dpkg-reconfigure --frontend noninteractive locales - #============================== # Set up TensorFlow / TensorPy #============================== -COPY third_party/docker/docker_install.sh /TensorPy/docker_install.sh +COPY install.sh /TensorPy/install.sh COPY requirements.txt /TensorPy/ COPY setup.py /TensorPy/ COPY tensorpy /TensorPy/tensorpy/ COPY examples /TensorPy/examples/ -COPY third_party/docker /TensorPy/third_party/docker/ -COPY third_party/docker/run_docker_test.sh /TensorPy/ -RUN cd /TensorPy && ls && ./third_party/docker/docker_install.sh +COPY integrations/docker/run_docker_test.sh /TensorPy/ +RUN cd /TensorPy && ls && ./install.sh RUN cd /TensorPy && pip install -r requirements.txt #=================== # Create entrypoint #=================== -COPY third_party/docker/docker-entrypoint.sh / +COPY integrations/docker/docker-entrypoint.sh / ENTRYPOINT ["/docker-entrypoint.sh"] CMD ["/bin/bash"] diff --git a/LICENSE b/LICENSE index 3ed9a1a..107c651 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ The MIT License (MIT) -Copyright (c) 2017 Michael Mintz +Copyright (c) 2018 Michael Mintz Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 62d089b..56b21ec 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ![](http://cdn2.hubspot.net/hubfs/100006/images/tensorpy_logo_4_p.png "TensorPy") # TensorPy -[![pypi](https://img.shields.io/pypi/v/tensorpy.svg)](https://pypi.python.org/pypi/tensorpy) [![Python version](https://img.shields.io/badge/python-2.7,_3.*-22AADD.svg "Python version")](https://docs.python.org/2/) [![MIT License](http://img.shields.io/badge/license-MIT-22BBCC.svg "MIT License")](https://github.com/TensorPy/TensorPy/blob/master/LICENSE) [![Join the chat at https://gitter.im/TensorPy/Lobby](https://badges.gitter.im/TensorPy/TensorPy.svg)](https://gitter.im/TensorPy/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![GitHub stars](https://img.shields.io/github/stars/TensorPy/TensorPy.svg "GitHub stars")](https://github.com/TensorPy/TensorPy/stargazers) +[![pypi](https://img.shields.io/pypi/v/tensorpy.svg)](https://pypi.python.org/pypi/tensorpy) [![Python version](https://img.shields.io/badge/python-3.5,_3.6,_3.7-22AADD.svg "Python version")](https://docs.python.org/2/) [![Join the chat at https://gitter.im/TensorPy/Lobby](https://badges.gitter.im/TensorPy/TensorPy.svg)](https://gitter.im/TensorPy/Lobby?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) **Easy Image Classification with TensorFlow** @@ -9,16 +9,19 @@ (**[Watch the 2-minute tutorial on YouTube](https://www.youtube.com/watch?v=lVtzaHcUE7Q)**) -Now runs **much faster** since video released! +### Requirements: -You can use TensorPy to classify images by simply passing a URL on the command line, or by using TensorPy in your Python programs. **[TensorFlow](https://www.tensorflow.org/)** does all the real work. TensorPy also simplifies TensorFlow installation by automating several setup steps into a single script (See **[install.sh](https://github.com/TensorPy/TensorPy/blob/master/install.sh)** and **[python3_install.sh](https://github.com/TensorPy/TensorPy/blob/master/python3_install.sh)** for details). +* A Mac or Linux machine +* Python 3.5, 3.6, or 3.7 + +You can use TensorPy to classify images by simply passing a URL on the command line, or by using TensorPy in your Python programs. **[TensorFlow](https://www.tensorflow.org/)** does all the real work. TensorPy also simplifies TensorFlow installation by automating several setup steps into a single script (See **[install.sh](https://github.com/TensorPy/TensorPy/blob/master/install.sh)** for details). (Read **[how_tensorpy_works](https://github.com/TensorPy/TensorPy/blob/master/help_docs/how_tensorpy_works.md)** for a detailed explanation of how TensorPy works.) ## Setup Steps for Mac & Ubuntu/Linux -(**Windows & Docker users**: See the **[Docker ReadMe](https://github.com/TensorPy/TensorPy/blob/master/third_party/docker/ReadMe.md)** for running on a Docker machine. Windows requires Docker to run TensorFlow.) +(**Windows & Docker users**: See the **[Docker ReadMe](https://github.com/TensorPy/TensorPy/blob/master/integrations/docker/ReadMe.md)** for running on a Docker machine. Windows requires Docker to run TensorFlow.) #### **Step 1:** Create and activate a virtual environment named "tensorpy" @@ -33,20 +36,16 @@ cd TensorPy #### **Step 3:** Install TensorPy, TensorFlow, and ImageNet/Inception -For **Python 2.7** users, use **[install.sh](https://github.com/TensorPy/TensorPy/blob/master/install.sh)** to install everything you need. +Use **[install.sh](https://github.com/TensorPy/TensorPy/blob/master/install.sh)** to install everything you need. ```bash ./install.sh ``` -For **Python 3** users, use **[python3_install.sh](https://github.com/TensorPy/TensorPy/blob/master/python3_install.sh)** to install everything you need. - -```bash -./python3_install.sh -``` - #### **Step 4:** Run the examples +(NOTE: Run times may vary depending on your Internet connection and computer's CPU speed.) + Classify a single image from a URL: ```bash @@ -79,8 +78,6 @@ classify examples/images/ #### **Examples in Python programs:** -*(**NOTE**: If you're using Python 3 instead of Python 2.7, replace "``python``" with "``python3``" on the command line.)* - Classify an image from a local file path using a Python script: (See **[test_python_file_classify.py](https://github.com/TensorPy/TensorPy/blob/master/examples/test_python_file_classify.py)** for details.) ```bash diff --git a/help_docs/how_tensorpy_works.md b/help_docs/how_tensorpy_works.md index b01300e..0d76f96 100755 --- a/help_docs/how_tensorpy_works.md +++ b/help_docs/how_tensorpy_works.md @@ -1,5 +1,7 @@ ### How TensorPy Works (Detailed Explanation) +(NOTE: Run times may vary depending on your Internet connection and computer's CPU speed.) + Once TensorPy is installed with **[install.sh](https://github.com/TensorPy/TensorPy/blob/master/install.sh)**, a command called ``classify`` is added to your command line, which takes a URL as input. When called, TensorPy determines if that URL links to an image or a web image. If it's an image, TensorPy downloads the image to a new folder called ``downloads_folder``. From there, the image is converted to a JPEG. Then, the image is fed to the local **[tensorpy/classify_image.py](https://github.com/TensorPy/TensorPy/blob/master/tensorpy/classify_image.py)** which tells TensorFlow to use the ImageNet Inception database to classify the image and print out the result. If the ``classify`` command is called with a web page as input, then all images on that page (up to the limit defined in **[tensorpy/settings.py](https://github.com/TensorPy/TensorPy/blob/master/tensorpy/settings.py)**) will get downloaded to ``downloads_folder``, where TensorPy does the work listed above per image, with the exception of images smaller than the minimum size defined in tensorpy/settings.py (currently 50x50 pixels). Images that are too small will be skipped because results have shown that icons and other tiny images get extremely poor classification results. diff --git a/help_docs/pip_installation.md b/help_docs/pip_installation.md index 158a808..6ecdaad 100755 --- a/help_docs/pip_installation.md +++ b/help_docs/pip_installation.md @@ -1,13 +1,19 @@ ### Pip Installation Instructions -Ubuntu/Linux +Ubuntu/Linux: ```bash sudo apt-get install python-pip python-dev ``` -Mac OS X +Mac OS X: ```bash sudo easy_install pip ``` + +OR + +```bash +python -m pip install -U pip +``` diff --git a/help_docs/virtualenv_instructions.md b/help_docs/virtualenv_instructions.md index 2452237..692f620 100755 --- a/help_docs/virtualenv_instructions.md +++ b/help_docs/virtualenv_instructions.md @@ -1,15 +1,15 @@ ### Virtual Environment Setup Tutorial -First: +First, install virtualenv / virtualenvwrapper: ```bash -sudo pip install virtualenv -sudo pip install virtualenvwrapper +python -m pip install virtualenv +python -m pip install virtualenvwrapper export WORKON_HOME=$HOME/.virtualenvs source /usr/local/bin/virtualenvwrapper.sh ``` -Next, follow the command depending on the system you're using: +If you add ``source /usr/local/bin/virtualenvwrapper.sh`` to your local bash file (``~/.bash_profile`` on Mac, ``~/.bashrc`` on Linux), virtualenvwrapper commands will be available to you whenever you open a new command prompt. You can then use the following commands to make those changes active. Mac users: ``source ~/.bash_profile`` Linux users: ``source ~/.bashrc`` @@ -28,7 +28,6 @@ deactivate You can always jump back in later: -(If you're using ``virtualenvwrapper``): ```bash workon tensorpy ``` diff --git a/install.sh b/install.sh index 6fd187b..2062c23 100755 --- a/install.sh +++ b/install.sh @@ -1,21 +1,19 @@ # Installs TensorPy, TensorFlow, ImageNet, and required dependancies -# (Made for Python 2.7) -pip install --upgrade pip -echo "Installing TensorPy for Python 2.7:" +python -m pip install --upgrade pip +echo "Installing TensorPy:" pip install -r requirements.txt --upgrade -python setup.py install +python setup.py develop value="$(uname)" -if [ $value == "Linux" ] +if [ $value = "Linux" ] then echo "Initializing TensorFlow setup on a Linux machine..." - export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.2.1-cp27-none-linux_x86_64.whl + export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-1.14.0-cp27-none-linux_x86_64.whl pip install --ignore-installed --upgrade $TF_BINARY_URL -elif [ $value == "Darwin" ] +elif [ $value = "Darwin" ] then echo "Initializing TensorFlow setup on a MAC..." - export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/mac/cpu/tensorflow-1.2.1-py2-none-any.whl - pip install --ignore-installed --upgrade $TF_BINARY_URL + pip install --upgrade tensorflow else echo "Incompatible machine for TensorFlow. Exiting script..." fi diff --git a/third_party/ReadMe.md b/integrations/ReadMe.md similarity index 59% rename from third_party/ReadMe.md rename to integrations/ReadMe.md index 287ae25..75f693f 100755 --- a/third_party/ReadMe.md +++ b/integrations/ReadMe.md @@ -1,3 +1,3 @@ -## Third-Party / Integrations +## Integrations This folder contains TensorPy integrations diff --git a/third_party/docker/ReadMe.md b/integrations/docker/ReadMe.md similarity index 100% rename from third_party/docker/ReadMe.md rename to integrations/docker/ReadMe.md diff --git a/third_party/docker/docker-entrypoint.sh b/integrations/docker/docker-entrypoint.sh similarity index 100% rename from third_party/docker/docker-entrypoint.sh rename to integrations/docker/docker-entrypoint.sh diff --git a/third_party/docker/run_docker_test.sh b/integrations/docker/run_docker_test.sh similarity index 100% rename from third_party/docker/run_docker_test.sh rename to integrations/docker/run_docker_test.sh diff --git a/python3_install.sh b/python3_install.sh deleted file mode 100755 index 5cd5f40..0000000 --- a/python3_install.sh +++ /dev/null @@ -1,22 +0,0 @@ -# Installs TensorPy, TensorFlow, ImageNet, and required dependancies -# (Made for Python 3) - -pip3 install --upgrade pip -echo "Installing TensorPy for Python 3:" -pip3 install -r requirements.txt --upgrade -python3 setup.py install -value="$(uname)" -if [ $value == "Linux" ] -then - echo "Initializing TensorFlow setup on a Linux machine..." - pip3 install --upgrade tensorflow -elif [ $value == "Darwin" ] -then - echo "Initializing TensorFlow setup on a MAC..." - pip3 install --upgrade tensorflow -else - echo "Incompatible machine for TensorFlow. Exiting script..." -fi -echo "Downloading ImageNet Inception DB (for classifying images)..." -python3 tensorpy/download_imagenet.py -exit diff --git a/requirements.txt b/requirements.txt index e5f2f52..5f4fae2 100755 --- a/requirements.txt +++ b/requirements.txt @@ -1,5 +1,6 @@ -requests==2.18.1 -six==1.10.0 -Pillow==4.1.1 -BeautifulSoup4==4.6.0 --e . +tensorflow==1.15.4 +pip>=20.2.3 +six>=1.15.0 +requests>=2.24.0 +Pillow==7.2.0 +beautifulsoup4==4.9.2 diff --git a/setup.py b/setup.py index 5f767cf..863853e 100644 --- a/setup.py +++ b/setup.py @@ -5,21 +5,72 @@ """ from setuptools import setup, find_packages # noqa +import os +import sys + + +this_directory = os.path.abspath(os.path.dirname(__file__)) +long_description = None +try: + with open(os.path.join(this_directory, 'README.md'), 'rb') as f: + long_description = f.read().decode('utf-8') +except IOError: + long_description = 'Easy Image Classification with TensorFlow!' + +if sys.argv[-1] == 'publish': + reply = None + input_method = input + if not sys.version_info[0] >= 3: + input_method = raw_input # noqa + reply = str(input_method( + '>>> Confirm release PUBLISH to PyPI? (yes/no): ')).lower().strip() + if reply == 'yes': + print("\n*** Checking code health with flake8:\n") + flake8_status = os.system("flake8 --exclude=temp") + if flake8_status != 0: + print("\nWARNING! Fix flake8 issues before publishing to PyPI!\n") + sys.exit() + else: + print("*** No flake8 issues detected. Continuing...") + print("\n*** Rebuilding distribution packages: ***\n") + os.system('rm -f dist/*.egg; rm -f dist/*.tar.gz; rm -f dist/*.whl') + os.system('python setup.py sdist bdist_wheel') # Create new tar/wheel + print("\n*** Installing twine: *** (Required for PyPI uploads)\n") + os.system("python -m pip install --upgrade 'twine>=1.15.0'") + print("\n*** Installing tqdm: *** (Required for PyPI uploads)\n") + os.system("python -m pip install --upgrade 'tqdm>=4.49.0'") + print("\n*** Publishing The Release to PyPI: ***\n") + os.system('python -m twine upload dist/*') # Requires ~/.pypirc Keys + print("\n*** The Release was PUBLISHED SUCCESSFULLY to PyPI! :) ***\n") + else: + print("\n>>> The Release was NOT PUBLISHED to PyPI! <<<\n") + sys.exit() setup( name='tensorpy', - version='1.1.0', - url='http://tensorpy.com', + version='1.6.1', + description='Easy Image Classification with TensorFlow!', + long_description=long_description, + long_description_content_type='text/markdown', + url='https://github.com/TensorPy/TensorPy', + platforms=["Linux", "Unix", "Mac OS-X"], author='Michael Mintz', author_email='mdmintz@gmail.com', maintainer='Michael Mintz', - description='Easy Image Classification with TensorFlow!', - license='The MIT License', + license="MIT", + classifiers=[ + "Programming Language :: Python :: 3.5", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + ], + python_requires='>=3.5, <3.8', install_requires=[ - 'requests==2.18.1', - 'six==1.10.0', - 'Pillow==4.1.1', - 'BeautifulSoup4==4.6.0', + 'tensorflow==1.15.4', + 'pip>=20.2.3', + 'six>=1.15.0', + 'requests>=2.24.0', + 'Pillow==7.2.0', + 'beautifulsoup4==4.9.2', ], packages=['tensorpy'], entry_points={ diff --git a/tensorpy/classify.py b/tensorpy/classify.py index 39ff08e..518e97e 100644 --- a/tensorpy/classify.py +++ b/tensorpy/classify.py @@ -124,9 +124,9 @@ def main(): break if images_classified >= settings.MAX_IMAGES_PER_PAGE: - print("\n(NOTE: Exceeded page classification limit " - "of %d images per URL! Stopping early.)" % ( - settings.MAX_IMAGES_PER_PAGE)) + print("\n(NOTE: Exceeded page classification limit " + "of %d images per URL! Stopping early.)" % ( + settings.MAX_IMAGES_PER_PAGE)) if images_classified == 0: print("\nCould not find images to classify on the page! " diff --git a/tensorpy/classify_image.py b/tensorpy/classify_image.py index 40a05a8..2c20196 100644 --- a/tensorpy/classify_image.py +++ b/tensorpy/classify_image.py @@ -13,7 +13,7 @@ os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2' FLAGS = tf.app.flags.FLAGS -tf.logging.set_verbosity(tf.logging.ERROR) +tf.compat.v1.logging.set_verbosity(tf.compat.v1.logging.ERROR) tf.app.flags.DEFINE_string( 'model_dir', settings.IMAGENET_FOLDER, """Path to classify_image_graph_def.pb, """ @@ -126,4 +126,4 @@ def external_run(image): if __name__ == '__main__': - tf.app.run() + tf.compat.v1.app.run() diff --git a/tensorpy/download_imagenet.py b/tensorpy/download_imagenet.py index ab425e7..1dd49b3 100644 --- a/tensorpy/download_imagenet.py +++ b/tensorpy/download_imagenet.py @@ -26,6 +26,7 @@ def maybe_download_and_extract(): os.makedirs(dest_directory) filename = DATA_URL.split('/')[-1] filepath = os.path.join(dest_directory, filename) + print("ImageNet Inception DB filepath: %s" % filepath) if not os.path.exists(filepath): def _progress(count, block_size, total_size): sys.stdout.write('\r>> Downloading %s %.1f%%' % ( @@ -43,4 +44,4 @@ def main(_): maybe_download_and_extract() -tf.app.run() +tf.compat.v1.app.run() diff --git a/tensorpy/image_base.py b/tensorpy/image_base.py index 237b6bc..98aa7c1 100644 --- a/tensorpy/image_base.py +++ b/tensorpy/image_base.py @@ -14,9 +14,9 @@ def get_image_file_dimensions(file_name): - image = Image.open(file_name) - image_dimensions = image.size # (width, height) tuple - return image_dimensions + with Image.open(file_name) as image: + image_dimensions = image.size # (width, height) tuple + return image_dimensions def convert_image_file_to_jpg(file_name): @@ -26,15 +26,17 @@ def convert_image_file_to_jpg(file_name): outfile = f + ".jpg" if infile != outfile: try: - Image.open(infile).convert('RGBA').save(outfile, "JPEG") + with Image.open(infile) as image: + image.convert('RGB').save(outfile, "JPEG") except IOError: raise Exception("Cannot convert %s to jpg!" % file_name) def load_image_from_url(image_url): response = requests.get(image_url) - image = Image.open(StringIO(response.content)).convert('RGBA') - return image + with Image.open(StringIO(response.content)) as image: + image.convert('RGB') + return image def get_image_dimensions(image): diff --git a/third_party/docker/docker_install.sh b/third_party/docker/docker_install.sh deleted file mode 100755 index 8edc900..0000000 --- a/third_party/docker/docker_install.sh +++ /dev/null @@ -1,12 +0,0 @@ -# Installs TensorPy, TensorFlow, ImageNet, and required dependancies -# (Special Docker edition!) - -pip install --upgrade pip -echo "Installing TensorPy..." -python setup.py install -echo "Initializing TensorFlow setup on an Ubuntu Docker machine..." -export TF_BINARY_URL=https://storage.googleapis.com/tensorflow/linux/cpu/tensorflow-0.10.0-cp27-none-linux_x86_64.whl -pip install $TF_BINARY_URL -echo "Downloading ImageNet (image database for classifying images)..." -python tensorpy/download_imagenet.py -exit