pax_global_header00006660000000000000000000000064133375571060014524gustar00rootroot0000000000000052 comment=01f5999a6cfb485aeef2de81b41c69ae02ba4f63 bitmath-1.3.3.1/000077500000000000000000000000001333755710600133175ustar00rootroot00000000000000bitmath-1.3.3.1/.coveragerc000066400000000000000000000017361333755710600154470ustar00rootroot00000000000000# -*- mode: conf -*- [run] include = bitmath/__init__.py,bitmath/integrations.py [report] exclude_lines = # These should be impossible to trigger. raise ValueError."Invalid value given for 'system' parameter." raise ValueError."Instances mathematical base is an unsupported value raise ValueError."Can't parse string %s into a bitmath object # Don't test the __main__ entry point __main__ # Explicitly label a line as 'do not cover' pragma: no cover # Stuff to skip only on Python 2.x. Insert a line like:" # pragma: # PY2X no cover" And export the env var "PYVER" as "PY2X". To skip # certain things on only Py3.x export PYVER as PY3X # # Review: http://nedbatchelder.com/code/coverage/config.html#h_Syntax if you need a refresher # # BTW, the exports happen in the Makefile on lines like (for the 3.x tests): # # . $(NAME)env3/bin/activate && export PYVER=PY3X && nosetests-3.3 -v .... pragma: ${PYVER} no cover bitmath-1.3.3.1/.github/000077500000000000000000000000001333755710600146575ustar00rootroot00000000000000bitmath-1.3.3.1/.github/CONTRIBUTING.md000066400000000000000000000001671333755710600171140ustar00rootroot00000000000000Please see the [Contributing Guidelines](http://bitmath.readthedocs.org/en/latest/contributing.html) on Read The Docs. bitmath-1.3.3.1/.github/ISSUE_TEMPLATE.md000066400000000000000000000014751333755710600173730ustar00rootroot00000000000000> Please put all multi-line output into the ``` blocks. Feel free to > delete any part that does not apply to your issue. For *enhancement* > requests you may delete everything. DESCRIPTION of the issue. Please include full error messages. Include links to relevant documentation if there is a disparity between what you observed and what you expected: ``` Put stack traces or error messages here if you have any, delete this if you don't. ``` How to REPRODUCE the issue: 1. meow 2. bark 3. nyan 4. woof How REPRODUCIBLE (every time? intermittently? only in certain environments?): What you EXPECTED to happen: What ACTUALLY happened: VERSION of bitmath effected (git hashes are OK). Did you install from RPM, PyPi, source? * Version: * Install Source: Your OPERATING SYSTEM and the affected PYTHON VERSION: bitmath-1.3.3.1/.github/pull_request_template.md000066400000000000000000000011621333755710600216200ustar00rootroot00000000000000Short description: Adds or changes $FEATURE/DOCUMENTATION Longer description, this may help improve our documentation, please be as verbose as you wish: Longer paragraph that describes what this is intended for. Include reasons why this is a useful feature. For example: what use-cases would be enhanced by your proposed change, why you are submitting this proposal, etc. Include links to any relevant external documentation or apropos libraries this may interact with. If this is a documentation change, please explain what inaccuracy you are fixing and be sure to include a link to the current inaccurate documentation. bitmath-1.3.3.1/.gitignore000066400000000000000000000007531333755710600153140ustar00rootroot00000000000000# Emacs backup garbage *~ # setup/distutils MANIFEST build dist rpm-build # python *.py[cod] # C extensions *.so # Packages *.egg *.egg-info dist build eggs parts bin var sdist develop-eggs .installed.cfg lib lib64 __pycache__ # Installer logs pip-log.txt # Unit test / coverage reports .coverage .tox nosetests.xml # Translations *.mo # Mr Developer .mr.developer.cfg .project .pydevproject htmlcov cover bitmathenv docsite/build/html docsite/build/doctrees bitmathenv3 bitmathenv2 bitmath-1.3.3.1/.travis.yml000066400000000000000000000005471333755710600154360ustar00rootroot00000000000000language: python notifications: email: false branches: only: - master after_success: - coveralls matrix: include: - python: "2.7" env: CI=ci2 - python: "3.4" env: CI=ci3 - python: "3.5" env: CI=ci3 - python: "3.6" env: CI=ci3 - python: "3.7-dev" env: CI=ci3 script: make $CI install: "" bitmath-1.3.3.1/CODE_OF_CONDUCT.md000066400000000000000000000062211333755710600161170ustar00rootroot00000000000000# Contributor Covenant Code of Conduct ## Our Pledge In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. ## Our Standards Examples of behavior that contributes to creating a positive environment include: * Using welcoming and inclusive language * Being respectful of differing viewpoints and experiences * Gracefully accepting constructive criticism * Focusing on what is best for the community * Showing empathy towards other community members Examples of unacceptable behavior by participants include: * The use of sexualized language or imagery and unwelcome sexual attention or advances * Trolling, insulting/derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or electronic address, without explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Our Responsibilities Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. ## Scope This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at timbielawa@gmail.com. The project team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the project's leadership. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] [homepage]: http://contributor-covenant.org [version]: http://contributor-covenant.org/version/1/4/ bitmath-1.3.3.1/LICENSE000066400000000000000000000021141333755710600143220ustar00rootroot00000000000000The MIT License (MIT) Copyright © 2014 Tim Bielawa Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. bitmath-1.3.3.1/MANIFEST.in000066400000000000000000000001571333755710600150600ustar00rootroot00000000000000include README.rst LICENSE bitmath.1 NEWS.rst graft bitmath graft tests recursive-include docsite/source *.rst bitmath-1.3.3.1/Makefile000066400000000000000000000234151333755710600147640ustar00rootroot00000000000000######################################################## # Makefile for bitmath # # useful targets: # make sdist ---------------- produce a tarball # make rpm ----------------- produce RPMs # make docs ----------------- rebuild the manpages (results are checked in) # make pyflakes, make pycodestyle -- source code checks # make test ----------------- run all unit tests (export LOG=true for /tmp/ logging) ######################################################## # > VARIABLE = value # # Normal setting of a variable - values within it are recursively # expanded when the variable is USED, not when it's declared. # # > VARIABLE := value # # Setting of a variable with simple expansion of the values inside - # values within it are expanded at DECLARATION time. ######################################################## NAME := bitmath PKGNAME := python-$(NAME) # VERSION file provides one place to update the software version. VERSION := $(shell cat VERSION) RPMRELEASE = $(shell awk '/global _short_release/{print $$NF; exit}' $(RPMSPEC).in) RPMSPECDIR := . RPMSPEC := $(RPMSPECDIR)/$(PKGNAME).spec # This doesn't evaluate until it's called. The -D argument is the # directory of the target file ($@), kinda like `dirname`. ASCII2MAN = a2x -D $(dir $@) -d manpage -f manpage $< ASCII2HTMLMAN = a2x -D docs/html/man/ -d manpage -f xhtml MANPAGES := bitmath.1 ###################################################################### # Begin make targets ###################################################################### # Documentation. YAY!!!! docs: conf.py $(MANPAGES) docsite/source/index.rst cd docsite; make html; cd - # Add examples to the RTD docs by taking it from the README docsite/source/index.rst: docsite/source/index.rst.in README.rst VERSION @echo "#############################################" @echo "# Building $@ Now" @echo "#############################################" awk 'BEGIN{P=0} /^Examples/ { P=1} { if (P == 1) print $$0 }' README.rst | cat $< - > $@ # Regenerate %.1.asciidoc if %.1.asciidoc.in has been modified more # recently than %.1.asciidoc. %.1.asciidoc: %.1.asciidoc.in VERSION sed "s/%VERSION%/$(VERSION)/" $< > $@ # Regenerate %.1 if %.1.asciidoc or VERSION has been modified more # recently than %.1. (Implicitly runs the %.1.asciidoc recipe) %.1: %.1.asciidoc @echo "#############################################" @echo "# Building $@ NOW" @echo "#############################################" $(ASCII2MAN) viewdocs: docs xdg-open docsite/build/html/index.html viewcover: xdg-open cover/index.html conf.py: docsite/source/conf.py.in sed "s/%VERSION%/$(VERSION)/" $< > docsite/source/conf.py # Build the spec file on the fly. Substitute version numbers from the # canonical VERSION file. python-bitmath.spec: python-bitmath.spec.in sed "s/%VERSION%/$(VERSION)/" $< > $@ # Build the distutils setup file on the fly. setup.py: setup.py.in VERSION python-bitmath.spec.in sed -e "s/%VERSION%/$(VERSION)/" -e "s/%RELEASE%/$(RPMRELEASE)/" $< > $@ # Upload sources to pypi/pypi-test pypi: python ./setup.py sdist upload pypitest: python ./setup.py sdist upload -r test # usage example: make tag TAG=1.1.0-1 tag: git tag -s -m $(TAG) $(TAG) tests: uniquetestnames unittests pycodestyle pyflakes : unittests: @echo "#############################################" @echo "# Running Unit Tests" @echo "#############################################" nosetests -v --with-coverage --cover-html --cover-package=bitmath --cover-min-percentage=90 clean: @find . -type f -regex ".*\.py[co]$$" -delete @find . -type f \( -name "*~" -or -name "#*" \) -delete @rm -fR build cover dist rpm-build MANIFEST htmlcov .coverage bitmathenv bitmathenv2 bitmathenv3 docsite/build/html/ docsite/build/doctrees/ bitmath.egg-info pycodestyle: @echo "#############################################" @echo "# Running PEP8 Compliance Tests" @echo "#############################################" pycodestyle -v --ignore=E501,E722 bitmath/__init__.py tests/*.py pyflakes: @echo "#############################################" @echo "# Running Pyflakes Sanity Tests" @echo "# Note: most import errors may be ignored" @echo "#############################################" -pyflakes bitmath/__init__.py tests/*.py uniquetestnames: @echo "#############################################" @echo "# Running Unique TestCase checker" @echo "#############################################" ./tests/test_unique_testcase_names.sh install: clean python ./setup.py install mkdir -p /usr/share/man/man1/ gzip -9 -c bitmath.1 > /usr/share/man/man1/bitmath.1.gz sdist: setup.py clean @echo "#############################################" @echo "# Creating SDIST" @echo "#############################################" python setup.py sdist deb: setup.py clean git archive --format=tar --prefix=bitmath/ HEAD | gzip -9 > ../bitmath_$(VERSION).$(RPMRELEASE).orig.tar.gz debuild -us -uc rpmcommon: sdist python-bitmath.spec setup.py @echo "#############################################" @echo "# Building (S)RPM Now" @echo "#############################################" @mkdir -p rpm-build @cp dist/$(NAME)-$(VERSION).$(RPMRELEASE).tar.gz rpm-build/$(VERSION).$(RPMRELEASE).tar.gz srpm5: rpmcommon rpmbuild --define "_topdir %(pwd)/rpm-build" \ --define 'dist .el5' \ --define "_builddir %{_topdir}" \ --define "_rpmdir %{_topdir}" \ --define "_srcrpmdir %{_topdir}" \ --define "_specdir $(RPMSPECDIR)" \ --define "_sourcedir %{_topdir}" \ --define "_source_filedigest_algorithm 1" \ --define "_binary_filedigest_algorithm 1" \ --define "_binary_payload w9.gzdio" \ --define "_source_payload w9.gzdio" \ --define "_default_patch_fuzz 2" \ -bs $(RPMSPEC) @echo "#############################################" @echo "$(PKGNAME) SRPM is built:" @find rpm-build -maxdepth 2 -name '$(PKGNAME)*src.rpm' | awk '{print " " $$1}' @echo "#############################################" srpm: rpmcommon rpmbuild --define "_topdir %(pwd)/rpm-build" \ --define "_builddir %{_topdir}" \ --define "_rpmdir %{_topdir}" \ --define "_srcrpmdir %{_topdir}" \ --define "_specdir $(RPMSPECDIR)" \ --define "_sourcedir %{_topdir}" \ -bs $(RPMSPEC) @echo "#############################################" @echo "$(PKGNAME) SRPM is built:" @find rpm-build -maxdepth 2 -name '$(PKGNAME)*src.rpm' | awk '{print " " $$1}' @echo "#############################################" rpm: rpmcommon rpmbuild --define "_topdir %(pwd)/rpm-build" \ --define "_builddir %{_topdir}" \ --define "_rpmdir %{_topdir}" \ --define "_srcrpmdir %{_topdir}" \ --define "_specdir $(RPMSPECDIR)" \ --define "_sourcedir %{_topdir}" \ -ba $(RPMSPEC) @echo "#############################################" @echo "$(PKGNAME) RPMs are built:" @find rpm-build -maxdepth 2 -name '$(PKGNAME)*.rpm' | awk '{print " " $$1}' @echo "#############################################" virtualenv2: @echo "#############################################" @echo "# Creating a virtualenv" @echo "#############################################" virtualenv $(NAME)env2 --python=python2 . $(NAME)env2/bin/activate && pip install -r requirements.txt ci-unittests2: @echo "#############################################" @echo "# Running Unit Tests in virtualenv" @echo "# Using python: $(shell ./bitmathenv2/bin/python --version 2>&1)" @echo "#############################################" . $(NAME)env2/bin/activate && export PYVER=PY2X && nosetests -v --with-coverage --cover-html --cover-min-percentage=90 --cover-package=bitmath tests/ ci-list-deps2: @echo "#############################################" @echo "# Listing all pip deps" @echo "#############################################" . $(NAME)env2/bin/activate && pip freeze ci-pycodestyle2: @echo "#############################################" @echo "# Running PEP8 Compliance Tests in virtualenv" @echo "#############################################" . $(NAME)env2/bin/activate && pycodestyle -v --ignore=E501,E722 bitmath/__init__.py tests/*.py ci-pyflakes2: @echo "#################################################" @echo "# Running Pyflakes Compliance Tests in virtualenv" @echo "#################################################" . $(NAME)env2/bin/activate && pyflakes bitmath/__init__.py tests/*.py ci2: clean uniquetestnames virtualenv2 ci-list-deps2 ci-pycodestyle2 ci-pyflakes2 ci-unittests2 : virtualenv3: @echo "" @echo "#############################################" @echo "# Creating a virtualenv" @echo "#############################################" virtualenv $(NAME)env3 --python=python3 . $(NAME)env3/bin/activate && pip install -r requirements-py3.txt ci-unittests3: @echo "" @echo "#############################################" @echo "# Running Unit Tests in virtualenv" @echo "# Using python: $(shell ./bitmathenv3/bin/python --version 2>&1)" @echo "#############################################" . $(NAME)env3/bin/activate && export PYVER=PY3X && nosetests -v --with-coverage --cover-html --cover-package=bitmath tests/ ci-list-deps3: @echo "" @echo "#############################################" @echo "# Listing all pip deps" @echo "#############################################" . $(NAME)env3/bin/activate && pip freeze ci-pycodestyle3: @echo "" @echo "#############################################" @echo "# Running PEP8 Compliance Tests in virtualenv" @echo "#############################################" . $(NAME)env3/bin/activate && pycodestyle -v --ignore=E501,E722 bitmath/__init__.py tests/*.py ci-pyflakes3: @echo "" @echo "#################################################" @echo "# Running Pyflakes Compliance Tests in virtualenv" @echo "#################################################" . $(NAME)env3/bin/activate && pyflakes bitmath/__init__.py tests/*.py ci3: clean uniquetestnames virtualenv3 ci-list-deps3 ci-pycodestyle3 ci-pyflakes3 ci-unittests3 : ci: ci2 : ci-all: ci2 ci3 bitmath-1.3.3.1/NEWS.rst000066400000000000000000000247321333755710600146350ustar00rootroot00000000000000NEWS #### .. contents:: :depth: 1 :local: .. _bitmath-1.3.3-1: bitmath-1.3.3-1 *************** `bitmath-1.3.3-1 `__ was published on 2018-08-23. Project ======= Version 1.3.3 is a minor update primarily released to synchronize versions across platforms. Additionally there are small packaging updates to keep up with changing standards. Minor bug fixes and documentation tweaks are included as well. The project now has an official `Code of Conduct `_, as well as issue and pull request templates. What happened to bitmath 1.3.2? It only ever existed as an idea in source control. Changes ======= **Bug Fixes** `Alexander Kapshuna `_ has submitted `several fixes `_ since the last release. Thanks! * Packaging requirements fixes * Python 3 compatibility * Subclassing and Type checking fixes/improvements `Marcus Kazmierczak `_ submitted `a fix `_ for some broken documentation links. And `Dawid Gosławski `_ make sure our `documentation `_ is accurate. Thanks to all the bitmath contributors over the years! .. _bitmath-1.3.1-1: bitmath-1.3.1-1 *************** `bitmath-1.3.1-1 `__ was published on 2016-07-17. Changes ======= **Added Functionality** * New function: :func:`bitmath.parse_string_unsafe`, a less strict version of :func:`bitmath.parse_string`. Accepts inputs using *non-standard* prefix units (such as single-letter, or mis-capitalized units). * Inspired by `@darkblaze69 `_'s request in `#60 "Problems in parse_string" `_. Project ======= **Ubuntu** * Bitmath is now available for installation via Ubuntu Xenial, Wily, Vivid, Trusty, and Precise PPAs. * Ubuntu builds inspired by `@hkraal `_ reporting an `installation issue `_ on Ubuntu systems. **Documentation** * `Cleaned up a lot `_ of broken or re-directing links using output from the Sphinx ``make linkcheck`` command. .. _bitmath-1.3.0-1: bitmath-1.3.0-1 *************** `bitmath-1.3.0-1 `__ was published on 2016-01-08. Changes ======= **Bug Fixes** * Closed `GitHub Issue #55 `_ "best_prefix for negative values". Now :func:`bitmath.best_prefix` returns correct prefix units for negative values. Thanks `mbdm `_! .. _bitmath-1.2.4-1: bitmath-1.2.4-1 *************** `bitmath-1.2.4-1 `__ was published on 2015-11-30. Changes ======= **Added Functionality** * New bitmath module function: :func:`bitmath.query_device_capacity`. Create :class:`bitmath.Byte` instances representing the capacity of a block device. Support is presently limited to Linux and Mac. * The :func:`bitmath.parse_string` function now can parse 'octet' based units. Enhancement requested in `#53 parse french unit names `_ by `walidsa3d `_. **Bug Fixes** * `#49 `_ - Fix handling unicode input in the `bitmath.parse_string `__ function. Thanks `drewbrew `_! * `#50 `_ - Update the ``setup.py`` script to be python3.x compat. Thanks `ssut `_! Documentation ============= * The project documentation is now installed along with the bitmath library in RPM packages. Project ======= **Fedora/EPEL** Look for separate python3.x and python2.x packages coming soon to `Fedora `_ and `EPEL `_. This is happening because of the `initiative `_ to update the base Python implementation on Fedora to Python 3.x * `BZ1282560 `_ .. _bitmath-1.2.3-1: bitmath-1.2.3-1 *************** `bitmath-1.2.3-1 `__ was published on 2015-01-03. Changes ======= **Added Functionality** * New utility: ``progressbar`` integration: `bitmath.integrations.BitmathFileTransferSpeed `_. A more functional file transfer speed widget. Documentation ============= * The command-line ``bitmath`` tool now has `online documentation `_ * A full demo of the ``argparse`` and ``progressbar`` integrations has been written. Additionally, it includes a comprehensive demonstration of the full capabilities of the bitmath library. View it in the *Real Life Demos* `Creating Download Progress Bars `_ example. Project ======= **Tests** * Travis-CI had some issues with installing dependencies for the 3.x build unittests. These were fixed and the build status has returned back to normal. .. _bitmath-1.2.0-1: bitmath-1.2.0-1 *************** `bitmath-1.2.0-1 `__ was published on 2014-12-29. Changes ======= **Added Functionality** * New utility: ``argparse`` integration: `bitmath.BitmathType `_. Allows you to specify arguments as bitmath types. Documentation ============= * The command-line ``bitmath`` tool now has a `proper manpage `_ Project ======= **Tests** * The command-line ``bitmath`` tool is now properly unittested. Code coverage back to ~100%. .. _bitmath-1.1.0-0: bitmath-1.1.0-1 *************** `bitmath-1.1.0-1 `_ was published on 2014-12-20. * `GitHub Milestone Tracker for 1.1.0 `_ Changes ======= **Added Functionality** * New ``bitmath`` `command-line tool `_ added. Provides CLI access to basic unit conversion functions * New utility function `bitmath.parse_string `_ for parsing a human-readable string into a bitmath object. `Patch submitted `_ by new contributor `tonycpsu `_. .. _bitmath-1.0.8-1: bitmath-1.0.5-1 through 1.0.8-1 ******************************* `bitmath-1.0.8-1 `__ was published on 2014-08-14. * `GitHub Milestone Tracker for 1.0.8 `_ Major Updates ============= * bitmath has a proper documentation website up now on Read the Docs, check it out: `bitmath.readthedocs.io `_ * bitmath is now Python 3.x compatible * bitmath is now included in the `Extra Packages for Enterprise Linux `_ EPEL6 and EPEL7 repositories (`pkg info `_) * merged 6 `pull requests `_ from 3 `contributors `_ Bug Fixes ========= * fixed some math implementation bugs * `commutative multiplication `_ * `true division `_ Changes ======= **Added Functionality** * `best-prefix `_ guessing: automatic best human-readable unit selection * support for `bitwise operations `_ * `formatting customization `_ methods (including plural/singular selection) * exposed many more `instance attributes `_ (all instance attributes are usable in custom formatting) * a `context manager `_ for applying formatting to an entire block of code * utility functions for sizing `files `_ and `directories `_ * add `instance properties `_ equivalent to ``instance.to_THING()`` methods Project ======= **Tests** * Test suite is now implemented using `Python virtualenv's `_ for consistency across across platforms * Test suite now contains 150 unit tests. This is **110** more tests than the previous major release (`1.0.4-1 `__) * Test suite now runs on EPEL6 and EPEL7 * `Code coverage `_ is stable around 95-100% .. _bitmath-1.0.4-1: bitmath-1.0.4-1 *************** This is the first release of **bitmath**. `bitmath-1.0.4-1 `__ was published on 2014-03-20. Project ======= Available via: * `PyPi `_ * Fedora 19 * Fedora 20 bitmath had been under development for 12 days when the 1.0.4-1 release was made available. Debut Functionality =================== * Converting between **SI** and **NIST** prefix units (``GiB`` to ``kB``) * Converting between units of the same type (SI to SI, or NIST to NIST) * Basic arithmetic operations (subtracting 42KiB from 50GiB) * Rich comparison operations (``1024 Bytes == 1KiB``) * Sorting * Useful *console* and *print* representations bitmath-1.3.3.1/README.rst000066400000000000000000000317211333755710600150120ustar00rootroot00000000000000.. image:: https://api.travis-ci.org/tbielawa/bitmath.png :target: https://travis-ci.org/tbielawa/bitmath/ :align: right :height: 19 :width: 77 .. image:: https://coveralls.io/repos/tbielawa/bitmath/badge.png?branch=master :target: https://coveralls.io/r/tbielawa/bitmath?branch=master :align: right :height: 19 :width: 77 .. image:: https://readthedocs.org/projects/bitmath/badge/?version=latest :target: http://bitmath.rtfd.org/ :align: right :height: 19 :width: 77 bitmath ======= `bitmath `_ simplifies many facets of interacting with file sizes in various units. Originally focusing on file size unit conversion, functionality now includes: * Converting between **SI** and **NIST** prefix units (``kB`` to ``GiB``) * Converting between units of the same type (SI to SI, or NIST to NIST) * Automatic human-readable prefix selection (like in `hurry.filesize `_) * Basic arithmetic operations (subtracting 42KiB from 50GiB) * Rich comparison operations (``1024 Bytes == 1KiB``) * bitwise operations (``<<``, ``>>``, ``&``, ``|``, ``^``) * Reading a device's storage capacity (Linux/OS X support only) * `argparse `_ integration as a custom type * `progressbar `_ integration as a better file transfer speed widget * String parsing * Sorting In addition to the conversion and math operations, `bitmath` provides human readable representations of values which are suitable for use in interactive shells as well as larger scripts and applications. The format produced for these representations is customizable via the functionality included in stdlibs `string.format `_. In discussion we will refer to the NIST units primarily. I.e., instead of "megabyte" we will refer to "mebibyte". The former is ``10^3 = 1,000,000`` bytes, whereas the second is ``2^20 = 1,048,576`` bytes. When you see file sizes or transfer rates in your web browser, most of the time what you're really seeing are the base-2 sizes/rates. **Don't Forget!** The source for bitmath `is available on GitHub `_. And did we mention there's almost 200 unittests? `Check them out for yourself `_. Installation ============ The easiest way to install bitmath is via ``dnf`` (or ``yum``) if you're on a Fedora/RHEL based distribution. bitmath is available in the main Fedora repositories, as well as the `EPEL6 `_ and `EPEL7 `_ repositories. There are now dual python2.x and python3.x releases available. **Python 2.x**: .. code-block:: bash $ sudo dnf install python2-bitmath **Python 3.x**: .. code-block:: bash $ sudo dnf install python3-bitmath .. note:: **Upgrading**: If you have the old *python-bitmath* package installed presently, you could also run ``sudo dnf update python-bitmath`` instead **PyPi**: You could also install bitmath from `PyPi `_ if you like: .. code-block:: bash $ sudo pip install bitmath .. note:: **pip** installs need pip >= 1.1. To workaround this, `download bitmath `_, from PyPi and then ``pip install bitmath-x.y.z.tar.gz``. See `issue #57 `_ for more information. **PPA**: Ubuntu Xenial, Wily, Vivid, Trusty, and Precise users can install bitmath from the `launchpad PPA `_: .. code-block:: bash $ sudo add-apt-repository ppa:tbielawa/bitmath $ sudo apt-get update $ sudo apt-get install python-bitmath **Source**: Or, if you want to install from source: .. code-block:: bash $ sudo python ./setup.py install If you want the bitmath manpage installed as well: .. code-block:: bash $ sudo make install Documentation ============= The main documentation lives at `http://bitmath.readthedocs.org/en/latest/ `_. Topics include: * The ``bitmath`` Module * Utility Functions * Context Managers * Module Variables * ``argparse`` integration * ``progressbar`` integration * The ``bitmath`` command-line Tool * Classes * Initializing * Available Classes * Class Methods * Instances * Instance Attributes * Instance Methods * Instance Properties * The Formatting Mini-Language * Getting Started * Tables of Supported Operations * Basic Math * Unit Conversion * Rich Comparison * Sorting * Real Life Examples * Download Speeds * Calculating how many files fit on a device * Printing Human-Readable File Sizes in Python * Calculating Linux BDP and TCP Window Scaling * Contributing to bitmath * Appendices * Rules for Math * On Units * Who uses Bitmath * Related Projects * NEWS * Copyright Examples ======== Arithmetic ---------- .. code-block:: python >>> import bitmath >>> log_size = bitmath.kB(137.4) >>> log_zipped_size = bitmath.Byte(987) >>> print "Compression saved %s space" % (log_size - log_zipped_size) Compression saved 136.413kB space >>> thumb_drive = bitmath.GiB(12) >>> song_size = bitmath.MiB(5) >>> songs_per_drive = thumb_drive / song_size >>> print songs_per_drive 2457.6 Convert Units ------------- File size unit conversion: .. code-block:: python >>> from bitmath import * >>> dvd_size = GiB(4.7) >>> print "DVD Size in MiB: %s" % dvd_size.to_MiB() DVD Size in MiB: 4812.8 MiB Select a human-readable unit ---------------------------- .. code-block:: python >>> small_number = kB(100) >>> ugly_number = small_number.to_TiB() >>> print ugly_number 9.09494701773e-08 TiB >>> print ugly_number.best_prefix() 97.65625 KiB Rich Comparison --------------- .. code-block:: python >>> cd_size = MiB(700) >>> cd_size > dvd_size False >>> cd_size < dvd_size True >>> MiB(1) == KiB(1024) True >>> MiB(1) <= KiB(1024) True Sorting ------- .. code-block:: python >>> sizes = [KiB(7337.0), KiB(1441.0), KiB(2126.0), KiB(2178.0), KiB(2326.0), KiB(4003.0), KiB(48.0), KiB(1770.0), KiB(7892.0), KiB(4190.0)] >>> print sorted(sizes) [KiB(48.0), KiB(1441.0), KiB(1770.0), KiB(2126.0), KiB(2178.0), KiB(2326.0), KiB(4003.0), KiB(4190.0), KiB(7337.0), KiB(7892.0)] Custom Formatting ----------------- * Use of the custom formatting system * All of the available instance properties Example: .. code-block:: python >>> longer_format = """Formatting attributes for %s ...: This instances prefix unit is {unit}, which is a {system} type unit ...: The unit value is {value} ...: This value can be truncated to just 1 digit of precision: {value:.1f} ...: In binary this looks like: {binary} ...: The prefix unit is derived from a base of {base} ...: Which is raised to the power {power} ...: There are {bytes} bytes in this instance ...: The instance is {bits} bits large ...: bytes/bits without trailing decimals: {bytes:.0f}/{bits:.0f}""" % str(ugly_number) >>> print ugly_number.format(longer_format) Formatting attributes for 5.96046447754 MiB This instances prefix unit is MiB, which is a NIST type unit The unit value is 5.96046447754 This value can be truncated to just 1 digit of precision: 6.0 In binary this looks like: 0b10111110101111000010000000 The prefix unit is derived from a base of 2 Which is raised to the power 20 There are 6250000.0 bytes in this instance The instance is 50000000.0 bits large bytes/bits without trailing decimals: 6250000/50000000 Utility Functions ----------------- **bitmath.getsize()** .. code-block:: python >>> print bitmath.getsize('python-bitmath.spec') 3.7060546875 KiB **bitmath.parse_string()** Parse a string with standard units: .. code-block:: python >>> import bitmath >>> a_dvd = bitmath.parse_string("4.7 GiB") >>> print type(a_dvd) >>> print a_dvd 4.7 GiB **bitmath.parse_string_unsafe()** Parse a string with ambiguous units: .. code-block:: python >>> import bitmath >>> a_gig = bitmath.parse_string_unsafe("1gb") >>> print type(a_gig) >>> a_gig == bitmath.GB(1) True >>> bitmath.parse_string_unsafe('1gb') == bitmath.parse_string_unsafe('1g') True **bitmath.query_device_capacity()** .. code-block:: python >>> import bitmath >>> with open('/dev/sda') as fp: ... root_disk = bitmath.query_device_capacity(fp) ... print root_disk.best_prefix() ... 238.474937439 GiB **bitmath.listdir()** .. code-block:: python >>> for i in bitmath.listdir('./tests/', followlinks=True, relpath=True, bestprefix=True): ... print i ... ('tests/test_file_size.py', KiB(9.2900390625)) ('tests/test_basic_math.py', KiB(7.1767578125)) ('tests/__init__.py', KiB(1.974609375)) ('tests/test_bitwise_operations.py', KiB(2.6376953125)) ('tests/test_context_manager.py', KiB(3.7744140625)) ('tests/test_representation.py', KiB(5.2568359375)) ('tests/test_properties.py', KiB(2.03125)) ('tests/test_instantiating.py', KiB(3.4580078125)) ('tests/test_future_math.py', KiB(2.2001953125)) ('tests/test_best_prefix_BASE.py', KiB(2.1044921875)) ('tests/test_rich_comparison.py', KiB(3.9423828125)) ('tests/test_best_prefix_NIST.py', KiB(5.431640625)) ('tests/test_unique_testcase_names.sh', Byte(311.0)) ('tests/.coverage', KiB(3.1708984375)) ('tests/test_best_prefix_SI.py', KiB(5.34375)) ('tests/test_to_built_in_conversion.py', KiB(1.798828125)) ('tests/test_to_Type_conversion.py', KiB(8.0185546875)) ('tests/test_sorting.py', KiB(4.2197265625)) ('tests/listdir_symlinks/10_byte_file_link', Byte(10.0)) ('tests/listdir_symlinks/depth1/depth2/10_byte_file', Byte(10.0)) ('tests/listdir_nosymlinks/depth1/depth2/10_byte_file', Byte(10.0)) ('tests/listdir_nosymlinks/depth1/depth2/1024_byte_file', KiB(1.0)) ('tests/file_sizes/kbytes.test', KiB(1.0)) ('tests/file_sizes/bytes.test', Byte(38.0)) ('tests/listdir/10_byte_file', Byte(10.0)) Formatting ---------- .. code-block:: python >>> with bitmath.format(fmt_str="[{value:.3f}@{unit}]"): ... for i in bitmath.listdir('./tests/', followlinks=True, relpath=True, bestprefix=True): ... print i[1] ... [9.290@KiB] [7.177@KiB] [1.975@KiB] [2.638@KiB] [3.774@KiB] [5.257@KiB] [2.031@KiB] [3.458@KiB] [2.200@KiB] [2.104@KiB] [3.942@KiB] [5.432@KiB] [311.000@Byte] [3.171@KiB] [5.344@KiB] [1.799@KiB] [8.019@KiB] [4.220@KiB] [10.000@Byte] [10.000@Byte] [10.000@Byte] [1.000@KiB] [1.000@KiB] [38.000@Byte] [10.000@Byte] ``argparse`` Integration ------------------------ Example script using ``bitmath.integrations.BitmathType`` as an argparser argument type: .. code-block:: python import argparse import bitmath parser = argparse.ArgumentParser( description="Arg parser with a bitmath type argument") parser.add_argument('--block-size', type=bitmath.integrations.BitmathType, required=True) results = parser.parse_args() print "Parsed in: {PARSED}; Which looks like {TOKIB} as a Kibibit".format( PARSED=results.block_size, TOKIB=results.block_size.Kib) If ran as a script the results would be similar to this: .. code-block:: bash $ python ./bmargparse.py --block-size 100MiB Parsed in: 100.0 MiB; Which looks like 819200.0 Kib as a Kibibit ``progressbar`` Integration --------------------------- Use ``bitmath.integrations.BitmathFileTransferSpeed`` as a ``progressbar`` file transfer speed widget to monitor download speeds: .. code-block:: python import requests import progressbar import bitmath import bitmath.integrations FETCH = 'https://www.kernel.org/pub/linux/kernel/v3.0/patch-3.16.gz' widgets = ['Bitmath Progress Bar Demo: ', ' ', progressbar.Bar(marker=progressbar.RotatingMarker()), ' ', bitmath.integrations.BitmathFileTransferSpeed()] r = requests.get(FETCH, stream=True) size = bitmath.Byte(int(r.headers['Content-Length'])) pbar = progressbar.ProgressBar(widgets=widgets, maxval=int(size), term_width=80).start() chunk_size = 2048 with open('/dev/null', 'wb') as fd: for chunk in r.iter_content(chunk_size): fd.write(chunk) if (pbar.currval + chunk_size) < pbar.maxval: pbar.update(pbar.currval + chunk_size) pbar.finish() If ran as a script the results would be similar to this: .. code-block:: bash $ python ./smalldl.py Bitmath Progress Bar Demo: ||||||||||||||||||||||||||||||||||||||||| 1.58 MiB/s bitmath-1.3.3.1/VERSION000066400000000000000000000000051333755710600143620ustar00rootroot000000000000001.3.3bitmath-1.3.3.1/bitmath.1000066400000000000000000000044521333755710600150360ustar00rootroot00000000000000'\" t .\" Title: bitmath .\" Author: [see the "AUTHOR" section] .\" Generator: DocBook XSL Stylesheets vsnapshot .\" Date: 08/23/2018 .\" Manual: python-bitmath .\" Source: bitmath 1.3.3 .\" Language: English .\" .TH "BITMATH" "1" "08/23/2018" "bitmath 1\&.3\&.3" "python\-bitmath" .\" ----------------------------------------------------------------- .\" * Define some portability stuff .\" ----------------------------------------------------------------- .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .\" http://bugs.debian.org/507673 .\" http://lists.gnu.org/archive/html/groff/2009-02/msg00013.html .\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ .ie \n(.g .ds Aq \(aq .el .ds Aq ' .\" ----------------------------------------------------------------- .\" * set default formatting .\" ----------------------------------------------------------------- .\" disable hyphenation .nh .\" disable justification (adjust text to left margin only) .ad l .\" ----------------------------------------------------------------- .\" * MAIN CONTENT STARTS HERE * .\" ----------------------------------------------------------------- .SH "NAME" bitmath \- command line utility for converting between prefix units .SH "SYNOPSIS" .sp bitmath [\-\-from\-stdin] [\-f IN_UNIT] [\-t OUT_UNIT] SIZE \&... .SH "DESCRIPTION" .sp Run it, give a number as the last parameter\&. Say what units you\(cqre giving/wanting, or not\&. .SH "OPTIONS" .PP \fB\-\-from\-stdin\fR .RS 4 Reads number from stdin rather than the cli\&. .RE .PP \fB\-f\fR \fIUNIT\fR, \fB\-\-from\fR \fIUNIT\fR .RS 4 The unit you are converting from\&. Default is \fBByte\fR\&. .RE .PP \fB\-t\fR \fIUNIT, \fR\fI\fB\-\-to\fR\fR\fI \*(AqUNIT\fR .RS 4 The unit you are converting to\&. The default is \fBauto\-selected\fR for best human\-readability\&. .RE .SH "AUTHOR" .sp Tim Bielawa .sp For a complete list of contributors, please visit the GitHub charts page\&. .SH "COPYRIGHT" .sp Copyright \(co 2014\-2016, Tim Bielawa\&. .sp bitmath is released under the terms of the "MIT" License\&. .SH "SEE ALSO" .sp \fBunits\fR(7) .sp \fBThe bitmath GitHub Project\fR \(em https://github\&.com/tbielawa/bitmath .sp \fBThe bitmath Documentation\fR \(em https://bitmath\&.readthedocs\&.org bitmath-1.3.3.1/bitmath.1.asciidoc.in000066400000000000000000000020751333755710600172170ustar00rootroot00000000000000bitmath(1) ========== :man source: bitmath :man version: %VERSION% :man manual: python-bitmath NAME ---- bitmath - command line utility for converting between prefix units SYNOPSIS -------- bitmath [--from-stdin] [-f IN_UNIT] [-t OUT_UNIT] SIZE ... DESCRIPTION ----------- Run it, give a number as the last parameter. Say what units you're giving/wanting, or not. OPTIONS ------- *--from-stdin*:: Reads number from stdin rather than the cli. *-f* 'UNIT', *--from* 'UNIT':: The unit you are converting from. Default is **Byte**. *-t* 'UNIT, *--to* 'UNIT':: The unit you are converting to. The default is **auto-selected** for best human-readability. AUTHOR ------ Tim Bielawa For a complete list of contributors, please visit the GitHub charts page. COPYRIGHT --------- Copyright © 2014-2016, Tim Bielawa. bitmath is released under the terms of the "MIT" License. SEE ALSO -------- *units*(7) *The bitmath GitHub Project* -- *The bitmath Documentation* -- bitmath-1.3.3.1/bitmath/000077500000000000000000000000001333755710600147475ustar00rootroot00000000000000bitmath-1.3.3.1/bitmath/__init__.py000066400000000000000000001446771333755710600171030ustar00rootroot00000000000000# -*- coding: utf-8 -*- # The MIT License (MIT) # # Copyright © 2014-2016 Tim Bielawa # See GitHub Contributors Graph for more information # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sub-license, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. # pylint: disable=bad-continuation,missing-docstring,invalid-name,line-too-long """Reference material: The bitmath homepage is located at: * http://bitmath.readthedocs.io/en/latest/ Prefixes for binary multiples: http://physics.nist.gov/cuu/Units/binary.html decimal and binary prefixes: man 7 units (from the Linux Documentation Project 'man-pages' package) BEFORE YOU GET HASTY WITH EXCLUDING CODE FROM COVERAGE: If you absolutely need to skip code coverage because of a strange Python 2.x vs 3.x thing, use the fancy environment substitution stuff from the .coverage RC file. In review: * If you *NEED* to skip a statement because of Python 2.x issues add the following:: # pragma: PY2X no cover * If you *NEED* to skip a statement because of Python 3.x issues add the following:: # pragma: PY3X no cover In this configuration, statements which are skipped in 2.x are still covered in 3.x, and the reverse holds true for tests skipped in 3.x. """ from __future__ import print_function import argparse import contextlib import fnmatch import math import numbers import os import os.path import platform import sys # For device capacity reading in query_device_capacity(). Only supported # on posix systems for now. Will be addressed in issue #52 on GitHub. if os.name == 'posix': import stat import fcntl import struct __all__ = ['Bit', 'Byte', 'KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB', 'Kib', 'Mib', 'Gib', 'Tib', 'Pib', 'Eib', 'kb', 'Mb', 'Gb', 'Tb', 'Pb', 'Eb', 'Zb', 'Yb', 'getsize', 'listdir', 'format', 'format_string', 'format_plural', 'parse_string', 'parse_string_unsafe', 'ALL_UNIT_TYPES', 'NIST', 'NIST_PREFIXES', 'NIST_STEPS', 'SI', 'SI_PREFIXES', 'SI_STEPS'] # Python 3.x compat if sys.version > '3': long = int # pragma: PY2X no cover unicode = str # pragma: PY2X no cover #: A list of all the valid prefix unit types. Mostly for reference, #: also used by the CLI tool as valid types ALL_UNIT_TYPES = ['Bit', 'Byte', 'kb', 'kB', 'Mb', 'MB', 'Gb', 'GB', 'Tb', 'TB', 'Pb', 'PB', 'Eb', 'EB', 'Zb', 'ZB', 'Yb', 'YB', 'Kib', 'KiB', 'Mib', 'MiB', 'Gib', 'GiB', 'Tib', 'TiB', 'Pib', 'PiB', 'Eib', 'EiB'] # ##################################################################### # Set up our module variables/constants ################################### # Internal: # Console repr(), ex: MiB(13.37), or kB(42.0) _FORMAT_REPR = '{unit_singular}({value})' # ################################## # Exposed: #: Constants for referring to NIST prefix system NIST = int(2) #: Constants for referring to SI prefix system SI = int(10) # ################################## #: All of the SI prefixes SI_PREFIXES = ['k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y'] #: Byte values represented by each SI prefix unit SI_STEPS = { 'Bit': 1 / 8.0, 'Byte': 1, 'k': 1000, 'M': 1000000, 'G': 1000000000, 'T': 1000000000000, 'P': 1000000000000000, 'E': 1000000000000000000, 'Z': 1000000000000000000000, 'Y': 1000000000000000000000000 } #: All of the NIST prefixes NIST_PREFIXES = ['Ki', 'Mi', 'Gi', 'Ti', 'Pi', 'Ei'] #: Byte values represented by each NIST prefix unit NIST_STEPS = { 'Bit': 1 / 8.0, 'Byte': 1, 'Ki': 1024, 'Mi': 1048576, 'Gi': 1073741824, 'Ti': 1099511627776, 'Pi': 1125899906842624, 'Ei': 1152921504606846976 } #: String representation, ex: ``13.37 MiB``, or ``42.0 kB`` format_string = "{value} {unit}" #: Pluralization behavior format_plural = False def os_name(): # makes unittesting platform specific code easier return os.name def capitalize_first(s): """Capitalize ONLY the first letter of the input `s` * returns a copy of input `s` with the first letter capitalized """ pfx = s[0].upper() _s = s[1:] return pfx + _s ###################################################################### # Base class for everything else class Bitmath(object): """The base class for all the other prefix classes""" # All the allowed input types valid_types = (int, float, long) def __init__(self, value=0, bytes=None, bits=None): """Instantiate with `value` by the unit, in plain bytes, or bits. Don't supply more than one keyword. default behavior: initialize with value of 0 only setting value: assert bytes is None and bits is None only setting bytes: assert value == 0 and bits is None only setting bits: assert value == 0 and bytes is None """ _raise = False if (value == 0) and (bytes is None) and (bits is None): pass # Setting by bytes elif bytes is not None: if (value == 0) and (bits is None): pass else: _raise = True # setting by bits elif bits is not None: if (value == 0) and (bytes is None): pass else: _raise = True if _raise: raise ValueError("Only one parameter of: value, bytes, or bits is allowed") self._do_setup() if bytes: # We were provided with the fundamental base unit, no need # to normalize self._byte_value = bytes self._bit_value = bytes * 8.0 elif bits: # We were *ALMOST* given the fundamental base # unit. Translate it into the fundamental unit then # normalize. self._byte_value = bits / 8.0 self._bit_value = bits else: # We were given a value representative of this *prefix # unit*. We need to normalize it into the number of bytes # it represents. self._norm(value) # We have the fundamental unit figured out. Set the 'pretty' unit self._set_prefix_value() def _set_prefix_value(self): self.prefix_value = self._to_prefix_value(self._byte_value) def _to_prefix_value(self, value): """Return the number of bits/bytes as they would look like if we converted *to* this unit""" return value / float(self._unit_value) def _setup(self): raise NotImplementedError("The base 'bitmath.Bitmath' class can not be used directly") def _do_setup(self): """Setup basic parameters for this class. `base` is the numeric base which when raised to `power` is equivalent to 1 unit of the corresponding prefix. I.e., base=2, power=10 represents 2^10, which is the NIST Binary Prefix for 1 Kibibyte. Likewise, for the SI prefix classes `base` will be 10, and the `power` for the Kilobyte is 3. """ (self._base, self._power, self._name_singular, self._name_plural) = self._setup() self._unit_value = self._base ** self._power def _norm(self, value): """Normalize the input value into the fundamental unit for this prefix type. :param number value: The input value to be normalized :raises ValueError: if the input value is not a type of real number """ if isinstance(value, self.valid_types): self._byte_value = value * self._unit_value self._bit_value = self._byte_value * 8.0 else: raise ValueError("Initialization value '%s' is of an invalid type: %s. " "Must be one of %s" % ( value, type(value), ", ".join(str(x) for x in self.valid_types))) ################################################################## # Properties #: The mathematical base of an instance base = property(lambda s: s._base) binary = property(lambda s: bin(int(s.bits))) """The binary representation of an instance in binary 1s and 0s. Note that for very large numbers this will mean a lot of 1s and 0s. For example, GiB(100) would be represented as:: 0b1100100000000000000000000000000000000000 That leading ``0b`` is normal. That's how Python represents binary. """ #: Alias for :attr:`binary` bin = property(lambda s: s.binary) #: The number of bits in an instance bits = property(lambda s: s._bit_value) #: The number of bytes in an instance bytes = property(lambda s: s._byte_value) #: The mathematical power of an instance power = property(lambda s: s._power) @property def system(self): """The system of units used to measure an instance""" if self._base == 2: return "NIST" elif self._base == 10: return "SI" else: # I don't expect to ever encounter this logic branch, but # hey, it's better to have extra test coverage than # insufficient test coverage. raise ValueError("Instances mathematical base is an unsupported value: %s" % ( str(self._base))) @property def unit(self): """The string that is this instances prefix unit name in agreement with this instance value (singular or plural). Following the convention that only 1 is singular. This will always be the singular form when :attr:`bitmath.format_plural` is ``False`` (default value). For example: >>> KiB(1).unit == 'KiB' >>> Byte(0).unit == 'Bytes' >>> Byte(1).unit == 'Byte' >>> Byte(1.1).unit == 'Bytes' >>> Gb(2).unit == 'Gbs' """ global format_plural if self.prefix_value == 1: # If it's a '1', return it singular, no matter what return self._name_singular elif format_plural: # Pluralization requested return self._name_plural else: # Pluralization NOT requested, and the value is not 1 return self._name_singular @property def unit_plural(self): """The string that is an instances prefix unit name in the plural form. For example: >>> KiB(1).unit_plural == 'KiB' >>> Byte(1024).unit_plural == 'Bytes' >>> Gb(1).unit_plural == 'Gb' """ return self._name_plural @property def unit_singular(self): """The string that is an instances prefix unit name in the singular form. For example: >>> KiB(1).unit_singular == 'KiB' >>> Byte(1024).unit == 'B' >>> Gb(1).unit_singular == 'Gb' """ return self._name_singular #: The "prefix" value of an instance value = property(lambda s: s.prefix_value) @classmethod def from_other(cls, item): """Factory function to return instances of `item` converted into a new instance of ``cls``. Because this is a class method, it may be called from any bitmath class object without the need to explicitly instantiate the class ahead of time. *Implicit Parameter:* * ``cls`` A bitmath class, implicitly set to the class of the instance object it is called on *User Supplied Parameter:* * ``item`` A :class:`bitmath.Bitmath` subclass instance *Example:* >>> import bitmath >>> kib = bitmath.KiB.from_other(bitmath.MiB(1)) >>> print kib KiB(1024.0) """ if isinstance(item, Bitmath): return cls(bits=item.bits) else: raise ValueError("The provided items must be a valid bitmath class: %s" % str(item.__class__)) ###################################################################### # The following implement the Python datamodel customization methods # # Reference: http://docs.python.org/2.7/reference/datamodel.html#basic-customization def __repr__(self): """Representation of this object as you would expect to see in an interpreter""" global _FORMAT_REPR return self.format(_FORMAT_REPR) def __str__(self): """String representation of this object""" global format_string return self.format(format_string) def format(self, fmt): """Return a representation of this instance formatted with user supplied syntax""" _fmt_params = { 'base': self.base, 'bin': self.bin, 'binary': self.binary, 'bits': self.bits, 'bytes': self.bytes, 'power': self.power, 'system': self.system, 'unit': self.unit, 'unit_plural': self.unit_plural, 'unit_singular': self.unit_singular, 'value': self.value } return fmt.format(**_fmt_params) ################################################################## # Guess the best human-readable prefix unit for representation ################################################################## def best_prefix(self, system=None): """Optional parameter, `system`, allows you to prefer NIST or SI in the results. By default, the current system is used (Bit/Byte default to NIST). Logic discussion/notes: Base-case, does it need converting? If the instance is less than one Byte, return the instance as a Bit instance. Else, begin by recording the unit system the instance is defined by. This determines which steps (NIST_STEPS/SI_STEPS) we iterate over. If the instance is not already a ``Byte`` instance, convert it to one. NIST units step up by powers of 1024, SI units step up by powers of 1000. Take integer value of the log(base=STEP_POWER) of the instance's byte value. E.g.: >>> int(math.log(Gb(100).bytes, 1000)) 3 This will return a value >= 0. The following determines the 'best prefix unit' for representation: * result == 0, best represented as a Byte * result >= len(SYSTEM_STEPS), best represented as an Exbi/Exabyte * 0 < result < len(SYSTEM_STEPS), best represented as SYSTEM_PREFIXES[result-1] """ # Use absolute value so we don't return Bit's for *everything* # less than Byte(1). From github issue #55 if abs(self) < Byte(1): return Bit.from_other(self) else: if type(self) is Byte: # pylint: disable=unidiomatic-typecheck _inst = self else: _inst = Byte.from_other(self) # Which table to consult? Was a preferred system provided? if system is None: # No preference. Use existing system if self.system == 'NIST': _STEPS = NIST_PREFIXES _BASE = 1024 elif self.system == 'SI': _STEPS = SI_PREFIXES _BASE = 1000 # Anything else would have raised by now else: # Preferred system provided. if system == NIST: _STEPS = NIST_PREFIXES _BASE = 1024 elif system == SI: _STEPS = SI_PREFIXES _BASE = 1000 else: raise ValueError("Invalid value given for 'system' parameter." " Must be one of NIST or SI") # Index of the string of the best prefix in the STEPS list _index = int(math.log(abs(_inst.bytes), _BASE)) # Recall that the log() function returns >= 0. This doesn't # map to the STEPS list 1:1. That is to say, 0 is handled with # special care. So if the _index is 1, we actually want item 0 # in the list. if _index == 0: # Already a Byte() type, so return it. return _inst elif _index >= len(_STEPS): # This is a really big number. Use the biggest prefix we've got _best_prefix = _STEPS[-1] elif 0 < _index < len(_STEPS): # There is an appropriate prefix unit to represent this _best_prefix = _STEPS[_index - 1] _conversion_method = getattr( self, 'to_%sB' % _best_prefix) return _conversion_method() ################################################################## def to_Bit(self): return Bit(self._bit_value) def to_Byte(self): return Byte(self._byte_value / float(NIST_STEPS['Byte'])) # Properties Bit = property(lambda s: s.to_Bit()) Byte = property(lambda s: s.to_Byte()) ################################################################## def to_KiB(self): return KiB(bits=self._bit_value) def to_Kib(self): return Kib(bits=self._bit_value) def to_kB(self): return kB(bits=self._bit_value) def to_kb(self): return kb(bits=self._bit_value) # Properties KiB = property(lambda s: s.to_KiB()) Kib = property(lambda s: s.to_Kib()) kB = property(lambda s: s.to_kB()) kb = property(lambda s: s.to_kb()) ################################################################## def to_MiB(self): return MiB(bits=self._bit_value) def to_Mib(self): return Mib(bits=self._bit_value) def to_MB(self): return MB(bits=self._bit_value) def to_Mb(self): return Mb(bits=self._bit_value) # Properties MiB = property(lambda s: s.to_MiB()) Mib = property(lambda s: s.to_Mib()) MB = property(lambda s: s.to_MB()) Mb = property(lambda s: s.to_Mb()) ################################################################## def to_GiB(self): return GiB(bits=self._bit_value) def to_Gib(self): return Gib(bits=self._bit_value) def to_GB(self): return GB(bits=self._bit_value) def to_Gb(self): return Gb(bits=self._bit_value) # Properties GiB = property(lambda s: s.to_GiB()) Gib = property(lambda s: s.to_Gib()) GB = property(lambda s: s.to_GB()) Gb = property(lambda s: s.to_Gb()) ################################################################## def to_TiB(self): return TiB(bits=self._bit_value) def to_Tib(self): return Tib(bits=self._bit_value) def to_TB(self): return TB(bits=self._bit_value) def to_Tb(self): return Tb(bits=self._bit_value) # Properties TiB = property(lambda s: s.to_TiB()) Tib = property(lambda s: s.to_Tib()) TB = property(lambda s: s.to_TB()) Tb = property(lambda s: s.to_Tb()) ################################################################## def to_PiB(self): return PiB(bits=self._bit_value) def to_Pib(self): return Pib(bits=self._bit_value) def to_PB(self): return PB(bits=self._bit_value) def to_Pb(self): return Pb(bits=self._bit_value) # Properties PiB = property(lambda s: s.to_PiB()) Pib = property(lambda s: s.to_Pib()) PB = property(lambda s: s.to_PB()) Pb = property(lambda s: s.to_Pb()) ################################################################## def to_EiB(self): return EiB(bits=self._bit_value) def to_Eib(self): return Eib(bits=self._bit_value) def to_EB(self): return EB(bits=self._bit_value) def to_Eb(self): return Eb(bits=self._bit_value) # Properties EiB = property(lambda s: s.to_EiB()) Eib = property(lambda s: s.to_Eib()) EB = property(lambda s: s.to_EB()) Eb = property(lambda s: s.to_Eb()) ################################################################## # The SI units go beyond the NIST units. They also have the Zetta # and Yotta prefixes. def to_ZB(self): return ZB(bits=self._bit_value) def to_Zb(self): return Zb(bits=self._bit_value) # Properties ZB = property(lambda s: s.to_ZB()) Zb = property(lambda s: s.to_Zb()) ################################################################## def to_YB(self): return YB(bits=self._bit_value) def to_Yb(self): return Yb(bits=self._bit_value) #: A new object representing this instance as a Yottabyte YB = property(lambda s: s.to_YB()) Yb = property(lambda s: s.to_Yb()) ################################################################## # Rich comparison operations ################################################################## def __lt__(self, other): if isinstance(other, numbers.Number): return self.prefix_value < other else: return self._byte_value < other.bytes def __le__(self, other): if isinstance(other, numbers.Number): return self.prefix_value <= other else: return self._byte_value <= other.bytes def __eq__(self, other): if isinstance(other, numbers.Number): return self.prefix_value == other else: return self._byte_value == other.bytes def __ne__(self, other): if isinstance(other, numbers.Number): return self.prefix_value != other else: return self._byte_value != other.bytes def __gt__(self, other): if isinstance(other, numbers.Number): return self.prefix_value > other else: return self._byte_value > other.bytes def __ge__(self, other): if isinstance(other, numbers.Number): return self.prefix_value >= other else: return self._byte_value >= other.bytes ################################################################## # Basic math operations ################################################################## # Reference: http://docs.python.org/2.7/reference/datamodel.html#emulating-numeric-types """These methods are called to implement the binary arithmetic operations (+, -, *, //, %, divmod(), pow(), **, <<, >>, &, ^, |). For instance, to evaluate the expression x + y, where x is an instance of a class that has an __add__() method, x.__add__(y) is called. The __divmod__() method should be the equivalent to using __floordiv__() and __mod__(); it should not be related to __truediv__() (described below). Note that __pow__() should be defined to accept an optional third argument if the ternary version of the built-in pow() function is to be supported.object.__complex__(self) """ def __add__(self, other): """Supported operations with result types: - bm + bm = bm - bm + num = num - num + bm = num (see radd) """ if isinstance(other, numbers.Number): # bm + num return other + self.value else: # bm + bm total_bytes = self._byte_value + other.bytes return (type(self))(bytes=total_bytes) def __sub__(self, other): """Subtraction: Supported operations with result types: - bm - bm = bm - bm - num = num - num - bm = num (see rsub) """ if isinstance(other, numbers.Number): # bm - num return self.value - other else: # bm - bm total_bytes = self._byte_value - other.bytes return (type(self))(bytes=total_bytes) def __mul__(self, other): """Multiplication: Supported operations with result types: - bm1 * bm2 = bm1 - bm * num = bm - num * bm = num (see rmul) """ if isinstance(other, numbers.Number): # bm * num result = self._byte_value * other return (type(self))(bytes=result) else: # bm1 * bm2 _other = other.value * other.base ** other.power _self = self.prefix_value * self._base ** self._power return (type(self))(bytes=_other * _self) """The division operator (/) is implemented by these methods. The __truediv__() method is used when __future__.division is in effect, otherwise __div__() is used. If only one of these two methods is defined, the object will not support division in the alternate context; TypeError will be raised instead.""" def __div__(self, other): """Division: Supported operations with result types: - bm1 / bm2 = num - bm / num = bm - num / bm = num (see rdiv) """ if isinstance(other, numbers.Number): # bm / num result = self._byte_value / other return (type(self))(bytes=result) else: # bm1 / bm2 return self._byte_value / float(other.bytes) def __truediv__(self, other): # num / bm return self.__div__(other) # def __floordiv__(self, other): # return NotImplemented # def __mod__(self, other): # return NotImplemented # def __divmod__(self, other): # return NotImplemented # def __pow__(self, other, modulo=None): # return NotImplemented ################################################################## """These methods are called to implement the binary arithmetic operations (+, -, *, /, %, divmod(), pow(), **, <<, >>, &, ^, |) with reflected (swapped) operands. These functions are only called if the left operand does not support the corresponding operation and the operands are of different types. [2] For instance, to evaluate the expression x - y, where y is an instance of a class that has an __rsub__() method, y.__rsub__(x) is called if x.__sub__(y) returns NotImplemented. These are the add/sub/mul/div methods for syntax where a number type is given for the LTYPE and a bitmath object is given for the RTYPE. E.g., 3 * MiB(3), or 10 / GB(42) """ def __radd__(self, other): # num + bm = num return other + self.value def __rsub__(self, other): # num - bm = num return other - self.value def __rmul__(self, other): # num * bm = bm return self * other def __rdiv__(self, other): # num / bm = num return other / float(self.value) def __rtruediv__(self, other): # num / bm = num return other / float(self.value) """Called to implement the built-in functions complex(), int(), long(), and float(). Should return a value of the appropriate type. If one of those methods does not support the operation with the supplied arguments, it should return NotImplemented. For bitmath purposes, these methods return the int/long/float equivalent of the this instances prefix Unix value. That is to say: - int(KiB(3.336)) would return 3 - long(KiB(3.336)) would return 3L - float(KiB(3.336)) would return 3.336 """ def __int__(self): """Return this instances prefix unit as an integer""" return int(self.prefix_value) def __long__(self): """Return this instances prefix unit as a long integer""" return long(self.prefix_value) # pragma: PY3X no cover def __float__(self): """Return this instances prefix unit as a floating point number""" return float(self.prefix_value) ################################################################## # Bitwise operations ################################################################## def __lshift__(self, other): """Left shift, ex: 100 << 2 A left shift by n bits is equivalent to multiplication by pow(2, n). A long integer is returned if the result exceeds the range of plain integers.""" shifted = int(self.bits) << other return type(self)(bits=shifted) def __rshift__(self, other): """Right shift, ex: 100 >> 2 A right shift by n bits is equivalent to division by pow(2, n).""" shifted = int(self.bits) >> other return type(self)(bits=shifted) def __and__(self, other): """"Bitwise and, ex: 100 & 2 bitwise and". Each bit of the output is 1 if the corresponding bit of x AND of y is 1, otherwise it's 0.""" andd = int(self.bits) & other return type(self)(bits=andd) def __xor__(self, other): """Bitwise xor, ex: 100 ^ 2 Does a "bitwise exclusive or". Each bit of the output is the same as the corresponding bit in x if that bit in y is 0, and it's the complement of the bit in x if that bit in y is 1.""" xord = int(self.bits) ^ other return type(self)(bits=xord) def __or__(self, other): """Bitwise or, ex: 100 | 2 Does a "bitwise or". Each bit of the output is 0 if the corresponding bit of x AND of y is 0, otherwise it's 1.""" ord = int(self.bits) | other return type(self)(bits=ord) ################################################################## def __neg__(self): """The negative version of this instance""" return (type(self))(-abs(self.prefix_value)) def __pos__(self): return (type(self))(abs(self.prefix_value)) def __abs__(self): return (type(self))(abs(self.prefix_value)) # def __invert__(self): # """Called to implement the unary arithmetic operations (-, +, abs() # and ~).""" # return NotImplemented ###################################################################### # First, the bytes... class Byte(Bitmath): """Byte based types fundamentally operate on self._bit_value""" def _setup(self): return (2, 0, 'Byte', 'Bytes') ###################################################################### # NIST Prefixes for Byte based types class KiB(Byte): def _setup(self): return (2, 10, 'KiB', 'KiBs') Kio = KiB class MiB(Byte): def _setup(self): return (2, 20, 'MiB', 'MiBs') Mio = MiB class GiB(Byte): def _setup(self): return (2, 30, 'GiB', 'GiBs') Gio = GiB class TiB(Byte): def _setup(self): return (2, 40, 'TiB', 'TiBs') Tio = TiB class PiB(Byte): def _setup(self): return (2, 50, 'PiB', 'PiBs') Pio = PiB class EiB(Byte): def _setup(self): return (2, 60, 'EiB', 'EiBs') Eio = EiB ###################################################################### # SI Prefixes for Byte based types class kB(Byte): def _setup(self): return (10, 3, 'kB', 'kBs') ko = kB class MB(Byte): def _setup(self): return (10, 6, 'MB', 'MBs') Mo = MB class GB(Byte): def _setup(self): return (10, 9, 'GB', 'GBs') Go = GB class TB(Byte): def _setup(self): return (10, 12, 'TB', 'TBs') To = TB class PB(Byte): def _setup(self): return (10, 15, 'PB', 'PBs') Po = PB class EB(Byte): def _setup(self): return (10, 18, 'EB', 'EBs') Eo = EB class ZB(Byte): def _setup(self): return (10, 21, 'ZB', 'ZBs') Zo = ZB class YB(Byte): def _setup(self): return (10, 24, 'YB', 'YBs') Yo = YB ###################################################################### # And now the bit types class Bit(Bitmath): """Bit based types fundamentally operate on self._bit_value""" def _set_prefix_value(self): self.prefix_value = self._to_prefix_value(self._bit_value) def _setup(self): return (2, 0, 'Bit', 'Bits') def _norm(self, value): """Normalize the input value into the fundamental unit for this prefix type""" self._bit_value = value * self._unit_value self._byte_value = self._bit_value / 8.0 ###################################################################### # NIST Prefixes for Bit based types class Kib(Bit): def _setup(self): return (2, 10, 'Kib', 'Kibs') class Mib(Bit): def _setup(self): return (2, 20, 'Mib', 'Mibs') class Gib(Bit): def _setup(self): return (2, 30, 'Gib', 'Gibs') class Tib(Bit): def _setup(self): return (2, 40, 'Tib', 'Tibs') class Pib(Bit): def _setup(self): return (2, 50, 'Pib', 'Pibs') class Eib(Bit): def _setup(self): return (2, 60, 'Eib', 'Eibs') ###################################################################### # SI Prefixes for Bit based types class kb(Bit): def _setup(self): return (10, 3, 'kb', 'kbs') class Mb(Bit): def _setup(self): return (10, 6, 'Mb', 'Mbs') class Gb(Bit): def _setup(self): return (10, 9, 'Gb', 'Gbs') class Tb(Bit): def _setup(self): return (10, 12, 'Tb', 'Tbs') class Pb(Bit): def _setup(self): return (10, 15, 'Pb', 'Pbs') class Eb(Bit): def _setup(self): return (10, 18, 'Eb', 'Ebs') class Zb(Bit): def _setup(self): return (10, 21, 'Zb', 'Zbs') class Yb(Bit): def _setup(self): return (10, 24, 'Yb', 'Ybs') ###################################################################### # Utility functions def best_prefix(bytes, system=NIST): """Return a bitmath instance representing the best human-readable representation of the number of bytes given by ``bytes``. In addition to a numeric type, the ``bytes`` parameter may also be a bitmath type. Optionally select a preferred unit system by specifying the ``system`` keyword. Choices for ``system`` are ``bitmath.NIST`` (default) and ``bitmath.SI``. Basically a shortcut for: >>> import bitmath >>> b = bitmath.Byte(12345) >>> best = b.best_prefix() Or: >>> import bitmath >>> best = (bitmath.KiB(12345) * 4201).best_prefix() """ if isinstance(bytes, Bitmath): value = bytes.bytes else: value = bytes return Byte(value).best_prefix(system=system) def query_device_capacity(device_fd): """Create bitmath instances of the capacity of a system block device Make one or more ioctl request to query the capacity of a block device. Perform any processing required to compute the final capacity value. Return the device capacity in bytes as a :class:`bitmath.Byte` instance. Thanks to the following resources for help figuring this out Linux/Mac ioctl's for querying block device sizes: * http://stackoverflow.com/a/12925285/263969 * http://stackoverflow.com/a/9764508/263969 :param file device_fd: A ``file`` object of the device to query the capacity of (as in ``get_device_capacity(open("/dev/sda"))``). :return: a bitmath :class:`bitmath.Byte` instance equivalent to the capacity of the target device in bytes. """ if os_name() != 'posix': raise NotImplementedError("'bitmath.query_device_capacity' is not supported on this platform: %s" % os_name()) s = os.stat(device_fd.name).st_mode if not stat.S_ISBLK(s): raise ValueError("The file descriptor provided is not of a device type") # The keys of the ``ioctl_map`` dictionary correlate to possible # values from the ``platform.system`` function. ioctl_map = { # ioctls for the "Linux" platform "Linux": { "request_params": [ # A list of parameters to calculate the block size. # # ( PARAM_NAME , FORMAT_CHAR , REQUEST_CODE ) ("BLKGETSIZE64", "L", 0x80081272) # Per , the BLKGETSIZE64 request returns a # 'u64' sized value. This is an unsigned 64 bit # integer C type. This means to correctly "buffer" the # result we need 64 bits, or 8 bytes, of memory. # # The struct module documentation include a reference # chart relating formatting characters to native C # Types. In this case, using the "native size", the # table tells us: # # * Character 'L' - Unsigned Long C Type (u64) - Loads into a Python int type # # Confirm this character is right by running (on Linux): # # >>> import struct # >>> print 8 == struct.calcsize('L') # # The result should be true as long as your kernel # headers define BLKGETSIZE64 as a u64 type (please # file a bug report at # https://github.com/tbielawa/bitmath/issues/new if # this does *not* work for you) ], # func is how the final result is decided. Because the # Linux BLKGETSIZE64 call returns the block device # capacity in bytes as an integer value, no extra # calculations are required. Simply return the value of # BLKGETSIZE64. "func": lambda x: x["BLKGETSIZE64"] }, # ioctls for the "Darwin" (Mac OS X) platform "Darwin": { "request_params": [ # A list of parameters to calculate the block size. # # ( PARAM_NAME , FORMAT_CHAR , REQUEST_CODE ) ("DKIOCGETBLOCKCOUNT", "L", 0x40086419), # Per : get media's block count - uint64_t # # As in the BLKGETSIZE64 example, an unsigned 64 bit # integer will use the 'L' formatting character ("DKIOCGETBLOCKSIZE", "I", 0x40046418) # Per : get media's block size - uint32_t # # This request returns an unsigned 32 bit integer, or # in other words: just a normal integer (or 'int' c # type). That should require 4 bytes of space for # buffering. According to the struct modules # 'Formatting Characters' chart: # # * Character 'I' - Unsigned Int C Type (uint32_t) - Loads into a Python int type ], # OS X doesn't have a direct equivalent to the Linux # BLKGETSIZE64 request. Instead, we must request how many # blocks (or "sectors") are on the disk, and the size (in # bytes) of each block. Finally, multiply the two together # to obtain capacity: # # n Block * y Byte # capacity (bytes) = ------- # 1 Block "func": lambda x: x["DKIOCGETBLOCKCOUNT"] * x["DKIOCGETBLOCKSIZE"] # This expression simply accepts a dictionary ``x`` as a # parameter, and then returns the result of multiplying # the two named dictionary items together. In this case, # that means multiplying ``DKIOCGETBLOCKCOUNT``, the total # number of blocks, by ``DKIOCGETBLOCKSIZE``, the size of # each block in bytes. } } platform_params = ioctl_map[platform.system()] results = {} for req_name, fmt, request_code in platform_params['request_params']: # Read the systems native size (in bytes) of this format type. buffer_size = struct.calcsize(fmt) # Construct a buffer to store the ioctl result in buffer = ' ' * buffer_size # This code has been ran on only a few test systems. If it's # appropriate, maybe in the future we'll add try/except # conditions for some possible errors. Really only for cases # where it would add value to override the default exception # message string. buffer = fcntl.ioctl(device_fd.fileno(), request_code, buffer) # Unpack the raw result from the ioctl call into a familiar # python data type according to the ``fmt`` rules. result = struct.unpack(fmt, buffer)[0] # Add the new result to our collection results[req_name] = result return Byte(platform_params['func'](results)) def getsize(path, bestprefix=True, system=NIST): """Return a bitmath instance in the best human-readable representation of the file size at `path`. Optionally, provide a preferred unit system by setting `system` to either `bitmath.NIST` (default) or `bitmath.SI`. Optionally, set ``bestprefix`` to ``False`` to get ``bitmath.Byte`` instances back. """ _path = os.path.realpath(path) size_bytes = os.path.getsize(_path) if bestprefix: return Byte(size_bytes).best_prefix(system=system) else: return Byte(size_bytes) def listdir(search_base, followlinks=False, filter='*', relpath=False, bestprefix=False, system=NIST): """This is a generator which recurses the directory tree `search_base`, yielding 2-tuples of: * The absolute/relative path to a discovered file * A bitmath instance representing the "apparent size" of the file. - `search_base` - The directory to begin walking down. - `followlinks` - Whether or not to follow symbolic links to directories - `filter` - A glob (see :py:mod:`fnmatch`) to filter results with (default: ``*``, everything) - `relpath` - ``True`` to return the relative path from `pwd` or ``False`` (default) to return the fully qualified path - ``bestprefix`` - set to ``False`` to get ``bitmath.Byte`` instances back instead. - `system` - Provide a preferred unit system by setting `system` to either ``bitmath.NIST`` (default) or ``bitmath.SI``. .. note:: This function does NOT return tuples for directory entities. .. note:: Symlinks to **files** are followed automatically """ for root, dirs, files in os.walk(search_base, followlinks=followlinks): for name in fnmatch.filter(files, filter): _path = os.path.join(root, name) if relpath: # RELATIVE path _return_path = os.path.relpath(_path, '.') else: # REAL path _return_path = os.path.realpath(_path) if followlinks: yield (_return_path, getsize(_path, bestprefix=bestprefix, system=system)) else: if os.path.isdir(_path) or os.path.islink(_path): pass else: yield (_return_path, getsize(_path, bestprefix=bestprefix, system=system)) def parse_string(s): """Parse a string with units and try to make a bitmath object out of it. String inputs may include whitespace characters between the value and the unit. """ # Strings only please if not isinstance(s, (str, unicode)): raise ValueError("parse_string only accepts string inputs but a %s was given" % type(s)) # get the index of the first alphabetic character try: index = list([i.isalpha() for i in s]).index(True) except ValueError: # If there's no alphabetic characters we won't be able to .index(True) raise ValueError("No unit detected, can not parse string '%s' into a bitmath object" % s) # split the string into the value and the unit val, unit = s[:index], s[index:] # see if the unit exists as a type in our namespace if unit == "b": unit_class = Bit elif unit == "B": unit_class = Byte else: if not (hasattr(sys.modules[__name__], unit) and isinstance(getattr(sys.modules[__name__], unit), type)): raise ValueError("The unit %s is not a valid bitmath unit" % unit) unit_class = globals()[unit] try: val = float(val) except ValueError: raise try: return unit_class(val) except: # pragma: no cover raise ValueError("Can't parse string %s into a bitmath object" % s) def parse_string_unsafe(s, system=SI): """Attempt to parse a string with ambiguous units and try to make a bitmath object out of it. This may produce inaccurate results if parsing shell output. For example `ls` may say a 2730 Byte file is '2.7K'. 2730 Bytes == 2.73 kB ~= 2.666 KiB. See the documentation for all of the important details. Note the following caveats: * All inputs are assumed to be byte-based (as opposed to bit based) * Numerical inputs (those without any units) are assumed to be a number of bytes * Inputs with single letter units (k, M, G, etc) are assumed to be SI units (base-10). Set the `system` parameter to `bitmath.NIST` to change this behavior. * Inputs with an `i` character following the leading letter (Ki, Mi, Gi) are assumed to be NIST units (base 2) * Capitalization does not matter """ if not isinstance(s, (str, unicode)) and \ not isinstance(s, numbers.Number): raise ValueError("parse_string_unsafe only accepts string/number inputs but a %s was given" % type(s)) ###################################################################### # Is the input simple to parse? Just a number, or a number # masquerading as a string perhaps? # Test case: raw number input (easy!) if isinstance(s, numbers.Number): # It's just a number. Assume bytes return Byte(s) # Test case: a number pretending to be a string if isinstance(s, (str, unicode)): try: # Can we turn it directly into a number? return Byte(float(s)) except ValueError: # Nope, this is not a plain number pass ###################################################################### # At this point: # - the input is also not just a number wrapped in a string # - nor is is just a plain number type # # We need to do some more digging around now to figure out exactly # what we were given and possibly normalize the input into a # format we can recognize. # First we'll separate the number and the unit. # # Get the index of the first alphabetic character try: index = list([i.isalpha() for i in s]).index(True) except ValueError: # pragma: no cover # If there's no alphabetic characters we won't be able to .index(True) raise ValueError("No unit detected, can not parse string '%s' into a bitmath object" % s) # Split the string into the value and the unit val, unit = s[:index], s[index:] # Don't trust anything. We'll make sure the correct 'b' is in place. unit = unit.rstrip('Bb') unit += 'B' # At this point we can expect `unit` to be either: # # - 2 Characters (for SI, ex: kB or GB) # - 3 Caracters (so NIST, ex: KiB, or GiB) # # A unit with any other number of chars is not a valid unit # SI if len(unit) == 2: # Has NIST parsing been requested? if system == NIST: # NIST units requested. Ensure the unit begins with a # capital letter and is followed by an 'i' character. unit = capitalize_first(unit) # Insert an 'i' char after the first letter _unit = list(unit) _unit.insert(1, 'i') # Collapse the list back into a 3 letter string unit = ''.join(_unit) unit_class = globals()[unit] else: # Default parsing (SI format) # # Edge-case checking: SI 'thousand' is a lower-case K if unit.startswith('K'): unit = unit.replace('K', 'k') elif not unit.startswith('k'): # Otherwise, ensure the first char is capitalized unit = capitalize_first(unit) # This is an SI-type unit if unit[0] in SI_PREFIXES: unit_class = globals()[unit] # NIST elif len(unit) == 3: unit = capitalize_first(unit) # This is a NIST-type unit if unit[:2] in NIST_PREFIXES: unit_class = globals()[unit] else: # This is not a unit we recognize raise ValueError("The unit %s is not a valid bitmath unit" % unit) try: unit_class except UnboundLocalError: raise ValueError("The unit %s is not a valid bitmath unit" % unit) return unit_class(float(val)) ###################################################################### # Contxt Managers @contextlib.contextmanager def format(fmt_str=None, plural=False, bestprefix=False): """Context manager for printing bitmath instances. ``fmt_str`` - a formatting mini-language compat formatting string. See the @properties (above) for a list of available items. ``plural`` - True enables printing instances with 's's if they're plural. False (default) prints them as singular (no trailing 's'). ``bestprefix`` - True enables printing instances in their best human-readable representation. False, the default, prints instances using their current prefix unit. """ if 'bitmath' not in globals(): import bitmath if plural: orig_fmt_plural = bitmath.format_plural bitmath.format_plural = True if fmt_str: orig_fmt_str = bitmath.format_string bitmath.format_string = fmt_str yield if plural: bitmath.format_plural = orig_fmt_plural if fmt_str: bitmath.format_string = orig_fmt_str def cli_script_main(cli_args): """ A command line interface to basic bitmath operations. """ choices = ALL_UNIT_TYPES parser = argparse.ArgumentParser( description='Converts from one type of size to another.') parser.add_argument('--from-stdin', default=False, action='store_true', help='Reads number from stdin rather than the cli') parser.add_argument( '-f', '--from', choices=choices, nargs=1, type=str, dest='fromunit', default=['Byte'], help='Input type you are converting from. Defaultes to Byte.') parser.add_argument( '-t', '--to', choices=choices, required=False, nargs=1, type=str, help=('Input type you are converting to. ' 'Attempts to detect best result if omitted.'), dest='tounit') parser.add_argument( 'size', nargs='*', type=float, help='The number to convert.') args = parser.parse_args(cli_args) # Not sure how to cover this with tests, or if the functionality # will remain in this form long enough for it to make writing a # test worth the effort. if args.from_stdin: # pragma: no cover args.size = [float(sys.stdin.readline()[:-1])] results = [] for size in args.size: instance = getattr(__import__( 'bitmath', fromlist=['True']), args.fromunit[0])(size) # If we have a unit provided then use it if args.tounit: result = getattr(instance, args.tounit[0]) # Otherwise use the best_prefix call else: result = instance.best_prefix() results.append(result) return results def cli_script(): # pragma: no cover # Wrapper around cli_script_main so we can unittest the command # line functionality for result in cli_script_main(sys.argv[1:]): print(result) if __name__ == '__main__': cli_script() bitmath-1.3.3.1/bitmath/integrations.py000066400000000000000000000100141333755710600200230ustar00rootroot00000000000000# -*- coding: utf-8 -*- # The MIT License (MIT) # # Copyright © 2014-2016 Tim Bielawa # See GitHub Contributors Graph for more information # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sub-license, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import bitmath import argparse import progressbar.widgets ###################################################################### # Integrations with 3rd party modules def BitmathType(bmstring): """An 'argument type' for integrations with the argparse module. For more information, see https://docs.python.org/2/library/argparse.html#type Of particular interest to us is this bit: ``type=`` can take any callable that takes a single string argument and returns the converted value I.e., ``type`` can be a function (such as this function) or a class which implements the ``__call__`` method. Example usage of the bitmath.BitmathType argparser type: >>> import bitmath >>> import argparse >>> parser = argparse.ArgumentParser() >>> parser.add_argument("--file-size", type=bitmath.BitmathType) >>> parser.parse_args("--file-size 1337MiB".split()) Namespace(file_size=MiB(1337.0)) Invalid usage includes any input that the bitmath.parse_string function already rejects. Additionally, **UNQUOTED** arguments with spaces in them are rejected (shlex.split used in the following examples to conserve single quotes in the parse_args call): >>> parser = argparse.ArgumentParser() >>> parser.add_argument("--file-size", type=bitmath.BitmathType) >>> import shlex >>> # The following is ACCEPTABLE USAGE: ... >>> parser.parse_args(shlex.split("--file-size '1337 MiB'")) Namespace(file_size=MiB(1337.0)) >>> # The following is INCORRECT USAGE because the string "1337 MiB" is not quoted! ... >>> parser.parse_args(shlex.split("--file-size 1337 MiB")) error: argument --file-size: 1337 can not be parsed into a valid bitmath object """ try: argvalue = bitmath.parse_string(bmstring) except ValueError: raise argparse.ArgumentTypeError("'%s' can not be parsed into a valid bitmath object" % bmstring) else: return argvalue ###################################################################### # Speed widget for integration with the Progress bar module class BitmathFileTransferSpeed(progressbar.widgets.Widget): """Widget for showing the transfer speed (useful for file transfers).""" __slots__ = ('system', 'format') def __init__(self, system=bitmath.NIST, format="{value:.2f} {unit}/s"): self.system = system self.format = format def update(self, pbar): """Updates the widget with the current NIST/SI speed. Basically, this calculates the average rate of update and figures out how to make a "pretty" prefix unit""" if pbar.seconds_elapsed < 2e-6 or pbar.currval < 2e-6: scaled = bitmath.Byte() else: speed = pbar.currval / pbar.seconds_elapsed scaled = bitmath.Byte(speed).best_prefix(system=self.system) return scaled.format(self.format) bitmath-1.3.3.1/debian/000077500000000000000000000000001333755710600145415ustar00rootroot00000000000000bitmath-1.3.3.1/debian/.gitignore000066400000000000000000000002151333755710600165270ustar00rootroot00000000000000files python-bitmath.debhelper.log python-bitmath.postinst.debhelper python-bitmath.prerm.debhelper python-bitmath.substvars python-bitmath/ bitmath-1.3.3.1/debian/changelog000066400000000000000000000004661333755710600164210ustar00rootroot00000000000000bitmath (1.3.1.1-1~ppa1~trusty1) trusty; urgency=low * New release -- Timothy Bielawa Sun, 17 Jul 2016 11:59:48 +0000 bitmath (1.3.0.2-1~ppa1~trusty1) trusty; urgency=low * First deb package release -- Timothy Bielawa Sat, 02 Jul 2016 15:52:37 +0000 bitmath-1.3.3.1/debian/compat000066400000000000000000000000021333755710600157370ustar00rootroot000000000000007 bitmath-1.3.3.1/debian/control000066400000000000000000000032201333755710600161410ustar00rootroot00000000000000Source: bitmath Maintainer: Tim Bielawa Section: python Priority: optional Build-Depends: python-setuptools (>= 0.6b3), python-all (>= 2.6.6-3), debhelper (>= 7.4.3) Standards-Version: 3.9.5 Homepage: http://bitmath.readthedocs.io/en/latest/ Vcs-Browser: https://github.com/tbielawa/bitmath Vcs-Git: https://github.com/tbielawa/bitmath.git Package: python-bitmath Architecture: all Homepage: http://bitmath.readthedocs.io/en/latest/ Depends: ${misc:Depends}, ${python:Depends} Description: Pythonic module for representing and manipulating file sizes bitmath simplifies many facets of interacting with file sizes in various units. Examples include: converting between SI and NIST prefix units (GiB to kB), converting between units of the same type (SI to SI, or NIST to NIST), basic arithmetic operations (subtracting 42KiB from 50GiB), and rich comparison operations (1024 Bytes == 1KiB), bitwise operations, sorting, automatic best human-readable prefix selection, and completely customizable formatting. . In addition to the conversion and math operations, bitmath provides human readable representations of values which are suitable for use in interactive shells as well as larger scripts and applications. It can also read the capacity of system storage devices. bitmath can parse strings (like "1 KiB") into proper objects and has support for integration with the argparse module as a custom argument type and the progressbar module as a custom file transfer speed widget. . bitmath is thoroughly unittested, with almost 200 individual tests (a number which is always increasing). bitmath's test-coverage is almost always at 100%. bitmath-1.3.3.1/debian/copyright000066400000000000000000000021141333755710600164720ustar00rootroot00000000000000The MIT License (MIT) Copyright © 2014 Tim Bielawa Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. bitmath-1.3.3.1/debian/docs000066400000000000000000000000441333755710600154120ustar00rootroot00000000000000README.rst NEWS.rst docsite/source/ bitmath-1.3.3.1/debian/python-bitmath.manpages000066400000000000000000000000121333755710600212160ustar00rootroot00000000000000bitmath.1 bitmath-1.3.3.1/debian/rules000077500000000000000000000007731333755710600156300ustar00rootroot00000000000000#!/usr/bin/make -f # This file was automatically generated by stdeb 0.8.5 at # Sat, 02 Jul 2016 15:52:37 +0000 %: dh $@ --with python2 --buildsystem=python_distutils override_dh_auto_clean: python setup.py clean -a find . -name \*.pyc -exec rm {} \; override_dh_auto_build: python setup.py build --force override_dh_auto_install: python setup.py install --force --root=debian/python-bitmath --no-compile -O0 --install-layout=deb override_dh_python2: dh_python2 --no-guessing-versions bitmath-1.3.3.1/debian/source/000077500000000000000000000000001333755710600160415ustar00rootroot00000000000000bitmath-1.3.3.1/debian/source/format000066400000000000000000000000141333755710600172470ustar00rootroot000000000000003.0 (quilt) bitmath-1.3.3.1/debian/source/options000066400000000000000000000000401333755710600174510ustar00rootroot00000000000000extend-diff-ignore="\.egg-info$"bitmath-1.3.3.1/doc-requirements.txt000066400000000000000000000000271333755710600173450ustar00rootroot00000000000000sphinxcontrib-showterm bitmath-1.3.3.1/docsite/000077500000000000000000000000001333755710600147515ustar00rootroot00000000000000bitmath-1.3.3.1/docsite/HEADERS000066400000000000000000000002541333755710600157500ustar00rootroot00000000000000# with overline, for parts * with overline, for chapters = for sections - for subsections ^ for subsubsections " for paragraphs | for anything smaller bitmath-1.3.3.1/docsite/Makefile000066400000000000000000000127671333755710600164260ustar00rootroot00000000000000# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = build # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: -rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 2>&1 | grep -v 'nonlocal image URI found:' @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/bitmath.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/bitmath.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/bitmath" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/bitmath" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -N -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." bitmath-1.3.3.1/docsite/source/000077500000000000000000000000001333755710600162515ustar00rootroot00000000000000bitmath-1.3.3.1/docsite/source/NEWS.rst000066400000000000000000000000351333755710600175550ustar00rootroot00000000000000.. include:: ../../NEWS.rst bitmath-1.3.3.1/docsite/source/appendices.rst000066400000000000000000000003341333755710600211160ustar00rootroot00000000000000Appendices ########## .. contents:: :depth: 3 :local: .. include:: appendices/mixed_math.rst .. include:: appendices/on_units.rst .. include:: appendices/who_uses.rst .. include:: appendices/related_projects.rst bitmath-1.3.3.1/docsite/source/appendices/000077500000000000000000000000001333755710600203645ustar00rootroot00000000000000bitmath-1.3.3.1/docsite/source/appendices/mixed_math.rst000066400000000000000000000170011333755710600232340ustar00rootroot00000000000000.. _appendix_math: Rules for Math ************** This section describes what we need to know to effectively use bitmath for arithmetic. Because bitmath allows the use of instances as operands on either side of the operator it is especially important to understand their behavior. Just as in normal every-day math, not all operations yield the same result if the operands are switched. E.g., ``1 - 2 = -1`` whereas ``2 - 1 = 1``. This section includes discussions of the results for each supported **mixed math** operation. For mixed math operations (i.e., an operation with a bitmath instance and a number type), implicit coercion **may** happen. That is to say, a bitmath instance will be converted to a number type. When coercion happens is determined by the following conditions and rules: 1. `Precedence and Associativity of Operators `_ in Python\ [#precedence]_ 2. Situational semantics -- some operations, though mathematically valid, do not make logical sense when applied to context. Terminology =========== The definitions describes some of the terminology used throughout this section. Coercion The act of converting operands into a common type to support arithmetic operations. Somewhat similar to how adding two fractions requires coercing each operand into having a common denominator. Specific to the bitmath domain, this concept means using an instance's prefix value for mixed-math. Operand The object(s) of a mathematical operation. That is to say, given ``1 + 2``, the operands would be **1** and **2**. Operator The mathematical operation to evaluate. Given ``1 + 2``, the operation would be addition, **+**. LHS *Left-hand side*. In discussion this specifically refers to the operand on the left-hand side of the operator. RHS *Right-hand side*. In discussion this specifically refers to the operand on the right-hand side of the operator. Two bitmath operands ==================== This section describes what happens when two bitmath instances are used as operands. There are three possible results from this type of operation. *Addition and subtraction* The result will be of the type of the LHS. *Multiplication* Supported, but yields strange results. .. code-block:: python :linenos: :emphasize-lines: 6,9 In [10]: first = MiB(5) In [11]: second = kB(2) In [12]: first * second Out[12]: MiB(10000.0) In [13]: (first * second).best_prefix() Out[13]: GiB(9.765625) As we can see on lines **6** and **9**, multiplying even two relatively small quantities together (``MiB(5)`` and ``kB(2)``) yields quite large results. Internally, this is implemented as: .. math:: (5 \cdot 2^{20}) \cdot (2 \cdot 10^{3}) = 10,485,760,000 B 10,485,760,000 B \cdot \dfrac{1 MiB}{1,048,576 B} = 10,000 MiB *Division* The result will be a number type due to unit cancellation. Mixed Types: Addition and Subtraction ===================================== This describes the behavior of addition and subtraction operations where one operand is a bitmath type and the other is a number type. Mixed-math addition and subtraction **always** return a type from the :py:mod:`numbers` family (integer, float, long, etc...). This rule is true regardless of the placement of the operands, with respect to the operator. **Discussion:** Why do ``100 - KiB(90)`` and ``KiB(100) - 90`` both yield a result of ``10.0`` and not another bitmath instance, such as ``KiB(10.0)``? When implementing the math part of the object datamodel customizations\ [#datamodel]_ there were two choices available: 1. Offer no support at all. Instead raise a :py:exc:`NotImplemented` exception. 2. Consistently apply coercion to the bitmath operand to produce a useful result (*useful* if you know the rules of the library). In the end it became a philosophical decision guided by scientific precedence. Put simply, bitmath uses the significance of the **least significant operand**, specifically the number-type operand because it lacks semantic significance. In application this means that we drop the semantic significance of the bitmath operand. That is to say, given an input like ``GiB(13.37)`` (equivalent to == 13.37 * 2\ :sup:`30`\ ), the only property used in calculations is the prefix value, ``13.37``. Numbers carry mathematical significance, in the form of precision, but what they lack is *semantic* (contextual) significance. A number by itself is just a measurement of an arbitrary quantity of *stuff*. In mixed-type math, bitmath effectively treats numbers as mathematical constants. A bitmath instance also has mathematical significance in that an instance is a measurement of a quantity (bits in this case) and that quantity has a measurable precision. But a bitmath instance is more than just a measurement, it is a specialized representation of a count of bits. This gives bitmath instances *semantic* significance as well. And so, in deciding how to handle mixed-type (really what we should say is mixed-significance) operations, we chose to model the behavior off of an already established set of rules. Those rules are the Rules of Significance Arithmetic\ [#significance]_. Let's look at an example of this in action: .. code-block:: python In [8]: num = 42 In [9]: bm = PiB(24) In [10]: print num + bm 66.0 Equivalently, divorcing the bitmath instance from it's value (this is coercion): .. code-block:: python In [12]: bm_value = bm.value In [13]: print num + bm_value 66.0 What it all boils down to is this: if we don't provide a unit then bitmath won't give us one back. There is no way for bitmath to guess what unit the operand was *intended* to carry. Therefore, the behavior of bitmath is **conservative**. It will meet us half way and do the math, but it will not return a unit in the result. Mixed Types: Multiplication and Division ======================================== **Multiplication** has *commutative* properties. This means that the ordering of the operands is **not significant**. Because of this fact bitmath allows arbitrary placement of the operands, treating the numeric operand as a constant. Here's an example demonstrating this. .. code-block:: python In [2]: 10 * KiB(43) Out[2]: KiB(430.0) In [3]: KiB(43) * 10 Out[3]: KiB(430.0) **Division**, however, *does not* have this commutative property. I.e., the placement of the operands **is** significant. Additionally, there is a semantic difference in division. Dividing a quantity (e.g. ``MiB(100)``) by a constant (``10``) makes complete sense. Conceptually (in the domain of bitmath), the intention of ``MiB(100) / 10)`` is to separate ``MiB(10)`` into **10** equal sized parts. .. code-block:: python In [4]: KiB(43) / 10 Out[4]: KiB(4.2998046875) The reverse operation does not maintain semantic validity. Stated differently, it does not make logical sense to divide a constant by a measured quantity of *stuff*. If you're still not clear on this, ask yourself what you would expect to get if you did this: .. math:: \dfrac{100}{kB(33)} = x Footnotes ========= .. [#precedence] For a less technical review of precedence and associativity, see `Programiz: Precedence and Associativity of Operators in Python `_ .. [#datamodel] `Python Datamodel Customization Methods `_ .. [#significance] https://en.wikipedia.org/wiki/Significance_arithmetic bitmath-1.3.3.1/docsite/source/appendices/on_units.rst000066400000000000000000000114051333755710600227550ustar00rootroot00000000000000.. _appendix_on_units: On Units ******** As previously stated, in this module you will find two very similar sets of classes available. These are the **NIST** and **SI** prefixes. The **NIST** prefixes are all base 2 and have an 'i' character in the middle. The **SI** prefixes are base 10 and have no 'i' character. For smaller values, these two systems of unit prefixes are roughly equivalent. The ``round()`` operations below demonstrate how close in a percent one "unit" of SI is to one "unit" of NIST. .. code-block:: python :linenos: :emphasize-lines: 7,15,23 In [15]: one_kilo = 1 * 10**3 In [16]: one_kibi = 1 * 2**10 In [17]: round(one_kilo / float(one_kibi), 2) Out[17]: 0.98 In [18]: one_tera = 1 * 10**12 In [19]: one_tebi = 1 * 2**40 In [20]: round(one_tera / float(one_tebi), 2) Out[20]: 0.91 In [21]: one_exa = 1 * 10**18 In [22]: one_exbi = 1 * 2**60 In [23]: round(one_exa / float(one_exbi), 2) Out[23]: 0.87 They begin as roughly equivalent, however as you can see (lines: **7**, **15**, and **23**), they diverge significantly for higher values. Why two unit systems? Why take the time to point this difference out? Why should you care? `The Linux Documentation Project `_ comments on that: Before these binary prefixes were introduced, it was fairly common to use k=1000 and K=1024, just like b=bit, B=byte. Unfortunately, the M is capital already, and cannot be capitalized to indicate binary-ness. At first that didn't matter too much, since memory modules and disks came in sizes that were powers of two, so everyone knew that in such contexts "kilobyte" and "megabyte" meant 1024 and 1048576 bytes, respectively. What originally was a sloppy use of the prefixes "kilo" and "mega" started to become regarded as the "real true meaning" when computers were involved. But then disk technology changed, and disk sizes became arbitrary numbers. After a period of uncertainty all disk manufacturers settled on the standard, namely k=1000, M=1000k, G=1000M. The situation was messy: in the 14k4 modems, k=1000; in the 1.44MB diskettes, M=1024000; etc. In 1998 the IEC approved the standard that defines the binary prefixes given above, enabling people to be precise and unambiguous. Thus, today, MB = 1000000B and MiB = 1048576B. In the free software world programs are slowly being changed to conform. When the Linux kernel boots and says:: hda: 120064896 sectors (61473 MB) w/2048KiB Cache the MB are megabytes and the KiB are kibibytes. - Source: ``man 7 units`` - http://man7.org/linux/man-pages/man7/units.7.html Furthermore, to quote the `National Institute of Standards and Technology (NIST) `_: "Once upon a time, computer professionals noticed that 2\ :sup:`10` was very nearly equal to 1000 and started using the SI prefix "kilo" to mean 1024. That worked well enough for a decade or two because everybody who talked kilobytes knew that the term implied 1024 bytes. But, almost overnight a much more numerous "everybody" bought computers, and the trade computer professionals needed to talk to physicists and engineers and even to ordinary people, most of whom know that a kilometer is 1000 meters and a kilogram is 1000 grams. "Then data storage for gigabytes, and even terabytes, became practical, and the storage devices were not constructed on binary trees, which meant that, for many practical purposes, binary arithmetic was less convenient than decimal arithmetic. The result is that today "everybody" does not "know" what a megabyte is. When discussing computer memory, most manufacturers use megabyte to mean 2\ :sup:`20` = 1 048 576 bytes, but the manufacturers of computer storage devices usually use the term to mean 1 000 000 bytes. Some designers of local area networks have used megabit per second to mean 1 048 576 bit/s, but all telecommunications engineers use it to mean 106 bit/s. And if two definitions of the megabyte are not enough, a third megabyte of 1 024 000 bytes is the megabyte used to format the familiar 90 mm (3 1/2 inch), "1.44 MB" diskette. The confusion is real, as is the potential for incompatibility in standards and in implemented systems. "Faced with this reality, the IEEE Standards Board decided that IEEE standards will use the conventional, internationally adopted, definitions of the SI prefixes. Mega will mean 1 000 000, except that the base-two definition may be used (if such usage is explicitly pointed out on a case-by-case basis) until such time that prefixes for binary multiples are adopted by an appropriate standards body." bitmath-1.3.3.1/docsite/source/appendices/related_projects.rst000066400000000000000000000074121333755710600244530ustar00rootroot00000000000000.. _appendix_related_projects: Related Projects **************** Bitmath is not the first project to tackle a challenge of this nature, handling units in a sane OOP approach. Several other Python libraries exist which provide similar functionality to bitmath. It only seems fair that we should point out these other libraries in case bitmath isn't the best fit for you. Magnitude ========= *Magnitude implements efficient computation with physical quantities. It allows you to do mathematical operations with them as if they were numbers, taking care of the units behind the scenes.* **Magnitide**, from Juan Reyero, is a *very* extensible library for working with a large variety of units (e.g., ``mile`` = *one mile*), as well as derived units (e.g., ``mile/hour``). Scaling, such as indicating one **mega** byte (``1 MB``) is also programmable with Magnitude. Juan is also kind enough to include a similar `"related projects" `_ section in his documentation. * `Magnitude GitHub Project `_ * `Magnitude Docs `_ hurry.filesize ============== *hurry.filesize a simple Python library that can take a number of bytes and returns a human-readable string with the size in it, in kilobytes (K), megabytes (M), etc.* **hurry.filesize** is very limited in functionality when compared to the other alternatives. However, it is an extremely simple and lightweight module. If you're looking for a library just for turning counts of bytes into human-readable strings, then hurry.filesize will be great for you. If you need any more functionality, such as greater control over :ref:`output formatting `, or :ref:`arithmetic calculations `, then you will find hurry.filesize lacking. This project has not updated since 2009, so I would not expect to see updates any time soon. * `PyPi Homepage & Download `_ SymPy - Units ============= *This module provides around 200 predefined units that are commonly used in the sciences. Additionally, it provides the ``Unit`` class which allows you to define your own units.* The **Units** module from the `SymPy `_ library is another option. Like **Magnitude**, the Units library is very extensible and includes around 200 built-in units by default. While technically it supports handling quantities such as ``1337 PiB``, this support must be configured by the user. In contrast, the bitmath module includes classes representing the full spectrum of byte and bit based units, out of the box. No conversion or derivation code required of the user. * `Units Homepage & Docs `_ * Download available through ``pip``, or your distribution's package system Unum ==== *Unum stands for 'unit-numbers'. It is a Python module that allows to define and manipulate true quantities, i.e. numbers with units such as 60 seconds, [...], 30 dollars etc. The module validates unit consistency in arithmetic expressions; it provides also automatic conversion and output formatting. Unum is designed to be reliable, easy-to-use, customizable and open to any unit definition.* **Unum**, by Pierre X. Denis, is another extensible library for unit manipulation. The module does not appear to have seen any activity in quite some time. Looking over the docs gives me the impression that it also has a tendency to pollute your namespace with objects like ``M`` and anything else it pre-defines. * `Unum Homepage and Docs `_ * `Unum Source Download `_ bitmath-1.3.3.1/docsite/source/appendices/who_uses.rst000066400000000000000000000024521333755710600227550ustar00rootroot00000000000000.. _appendix_who_uses: Who uses Bitmath **************** Shout-outs to all of the bitmath adopters out there I was able to identify: * `ClusterHQ's `_ `"Flocker" `_. A data volume manager for Dockerized applications * VMware's `vsphere `_ flocker storage driver * EMC's `scaleio `_ flocker storage driver * Dell Storage's `storage center block device `_ flocker driver * `TravelCRM `_ - Free CRM for travel companies - `Bitbucket `_ * `direscraw `_ by `Brian Mikolajczyk `_ for recovering lost files * `sizer `_ by `Calle Liljeholm `_. Calculating useable capacity in a flocker cluster bitmath-1.3.3.1/docsite/source/classes.rst000066400000000000000000000164131333755710600204450ustar00rootroot00000000000000.. _classes: .. currentmodule:: bitmath Classes ####### .. contents:: :depth: 3 :local: Available Classes ***************** There are two **fundamental** classes available, the :class:`Bit` and the :class:`Byte`. There are **24** other classes available, representing all the prefix units from **k** through **e** (*kilo/kibi* through *exa/exbi*). Classes with **'i'** in their names are **NIST** type classes. They were defined by the `National Institute of Standards and Technology (NIST) `_ as the 'Binary Prefix Units'. They are defined by increasing powers of 2. Classes without the **'i'** character are **SI** type classes. Though not formally defined by any standards organization, they follow the `International System of Units (SI) `_ pattern (commonly used to abbreviate base 10 values). You may hear these referred to as the "Decimal" or "SI" prefixes. Classes ending with *lower-case* **'b'** characters are **bit based**. Classes ending with upper-case **'B'** characters are **byte based**. Class inheritance is shown below in parentheses to make this more apparent: .. _classes_available: +---------------+--------------+ | NIST | SI | +===============+==============+ | ``Eib(Bit)`` | ``Eb(Bit)`` | +---------------+--------------+ | ``EiB(Byte)`` | ``EB(Byte)`` | +---------------+--------------+ | ``Gib(Bit)`` | ``Gb(Bit)`` | +---------------+--------------+ | ``GiB(Byte)`` | ``GB(Byte)`` | +---------------+--------------+ | ``Kib(Bit)`` | ``kb(Bit)`` | +---------------+--------------+ | ``KiB(Byte)`` | ``kB(Byte)`` | +---------------+--------------+ | ``Mib(Bit)`` | ``Mb(Bit)`` | +---------------+--------------+ | ``MiB(Byte)`` | ``MB(Byte)`` | +---------------+--------------+ | ``Pib(Bit)`` | ``Pb(Bit)`` | +---------------+--------------+ | ``PiB(Byte)`` | ``PB(Byte)`` | +---------------+--------------+ | ``Tib(Bit)`` | ``Tb(Bit)`` | +---------------+--------------+ | ``TiB(Byte)`` | ``TB(Byte)`` | +---------------+--------------+ .. note:: As per SI definition, the ``kB`` and ``kb`` classes begins with a *lower-case* **k** character. The majority of the functionality of bitmath object comes from their rich implementation of standard Python operations. You can use bitmath objects in **almost all** of the places you would normally use an integer or a float. See the :ref:`Table of Supported Operations ` and :ref:`Appendix: Rules for Math ` for more details. Initializing ************ .. class:: Bit([value=0[, bytes=None[, bits=None]]]) .. class:: Byte([value=0[, bytes=None[, bits=None]]]) .. class:: EB([value=0[, bytes=None[, bits=None]]]) .. class:: Eb([value=0[, bytes=None[, bits=None]]]) .. class:: EiB([value=0[, bytes=None[, bits=None]]]) .. class:: Eib([value=0[, bytes=None[, bits=None]]]) .. class:: GB([value=0[, bytes=None[, bits=None]]]) .. class:: Gb([value=0[, bytes=None[, bits=None]]]) .. class:: GiB([value=0[, bytes=None[, bits=None]]]) .. class:: Gib([value=0[, bytes=None[, bits=None]]]) .. class:: kB([value=0[, bytes=None[, bits=None]]]) .. class:: kb([value=0[, bytes=None[, bits=None]]]) .. class:: KiB([value=0[, bytes=None[, bits=None]]]) .. class:: Kib([value=0[, bytes=None[, bits=None]]]) .. class:: MB([value=0[, bytes=None[, bits=None]]]) .. class:: Mb([value=0[, bytes=None[, bits=None]]]) .. class:: MiB([value=0[, bytes=None[, bits=None]]]) .. class:: Mib([value=0[, bytes=None[, bits=None]]]) .. class:: PB([value=0[, bytes=None[, bits=None]]]) .. class:: Pb([value=0[, bytes=None[, bits=None]]]) .. class:: PiB([value=0[, bytes=None[, bits=None]]]) .. class:: Pib([value=0[, bytes=None[, bits=None]]]) .. class:: TB([value=0[, bytes=None[, bits=None]]]) .. class:: Tb([value=0[, bytes=None[, bits=None]]]) .. class:: TiB([value=0[, bytes=None[, bits=None]]]) .. class:: Tib([value=0[, bytes=None[, bits=None]]]) .. class:: YB([value=0[, bytes=None[, bits=None]]]) .. class:: Yb([value=0[, bytes=None[, bits=None]]]) .. class:: ZB([value=0[, bytes=None[, bits=None]]]) .. class:: Zb([value=0[, bytes=None[, bits=None]]]) .. class:: Bitmath([value=0[, bytes=None[, bits=None]]]) The ``value``, ``bytes``, and ``bits`` parameters are **mutually exclusive**. That is to say, you cannot instantiate a bitmath class using more than **one** of the parameters. Omitting any keyword argument defaults to behaving as if ``value`` was provided. :param int value: **Default: 0**. The value of the instance in *prefix units*. For example, if we were instantiating a ``bitmath.KiB`` object to represent 13.37 KiB, the ``value`` parameter would be **13.37**. For instance, ``k = bitmath.KiB(13.37)``. :param int bytes: The value of the instance as measured in bytes. :param int bits: The value of the instance as measured in bits. :raises ValueError: if more than one parameter is provided. The following code block demonstrates the 4 acceptable ways to instantiate a bitmath class. .. code-block:: python :linenos: :emphasize-lines: 4,7,11,15 >>> import bitmath # Omitting all keyword arguments defaults to 'value' behavior. >>> a = bitmath.KiB(1) # This is equivalent to the previous statement >>> b = bitmath.KiB(value=1) # We can also specify the initial value in bytes. # Recall, 1KiB = 1024 bytes >>> c = bitmath.KiB(bytes=1024) # Finally, we can specify exact number of bits in the # instance. Recall, 1024B = 8192b >>> d = bitmath.KiB(bits=8192) >>> a == b == c == d True Class Methods ************* Class Method: from_other() ========================== bitmath **class objects** have one public class method, :py:meth:`BitMathClass.from_other` which provides an alternative way to initialize a bitmath class. This method may be called on bitmath class objects directly. That is to say: you do not need to call this method on an instance of a bitmath class, however that is a valid use case. .. classmethod:: Byte.from_other(item) Instantiate any ``BitMathClass`` using another instance as reference for it's initial value. The ``from_other()`` class method has one required parameter: an instance of a bitmath class. :param BitMathInstance item: An instance of a bitmath class. :return: a bitmath instance of type ``BitMathClass`` equivalent in value to ``item`` :rtype: BitMathClass :raises TypeError: if ``item`` is not a valid :ref:`bitmath class ` In pure Python, this could also be written as: .. code-block:: python :linenos: :emphasize-lines: 3 >>> import bitmath >>> a_mebibyte = bitmath.MiB(1) >>> a_mebibyte_sized_kibibyte = bitmath.KiB(bytes=a_mebibyte.bytes) >>> a_mebibyte == a_mebibyte_sized_kibibyte True >>> print a_mebibyte, a_mebibyte_sized_kibibyte 1.0 MiB 1024.0 KiB Or, using the :py:meth:`BitMathClass.from_other` class method: .. code-block:: python :linenos: >>> a_mebibyte = bitmath.MiB(1) >>> a_big_kibibyte = bitmath.KiB.from_other(a_mebibyte) >>> a_mebibyte == a_big_kibibyte True >>> print a_mebibyte, a_big_kibibyte 1.0 MiB 1024.0 KiB bitmath-1.3.3.1/docsite/source/commandline.rst000066400000000000000000000033071333755710600212740ustar00rootroot00000000000000.. _command_line: The ``bitmath`` command-line Tool ################################# :mod:`bitmath` includes a CLI utility for easily converting units in a shell. For reference, there is also a manpage included, :manpage:`bitmath (1)`. Synopsis ******** .. code-block:: bash bitmath [--from-stdin] [-f IN_UNIT] [-t OUT_UNIT] VALUE ... Options ******* .. program:: bitmath .. option:: -f Specify the input unit to convert from. Defaults to :class:`bitmath.Byte`. .. option:: -t Specify the output unit to convert to. Defaults to the :ref:`best human-readable ` prefix unit. .. option:: --from-stdin Reads number from stdin rather than as a CLI argument. .. describe:: VALUE The value to convert. Examples ******** Convert ``1024`` into the best human-readable unit. Without specifying any ``from`` or ``to`` values this examples defaults to treating the input value as a :class:`bitmath.Byte`: .. code-block:: bash $ bitmath 1024 1.0 KiB Convert 1024 KiB into kBs: .. code-block:: bash $ bitmath -f KiB -t kb 1024 8388.608 kb Convert 1073741824 bytes into the best human-readable unit: .. code-block:: bash $ bitmath -f Byte 1073741824 1.0 GiB Use the :command:`stat` command to print the size of :file:`bitmath/__init__.py` in bytes, pipe the output into the :command:`bitmath` command, and print the result in MBs: .. code-block:: bash $ stat -c '%s' bitmath/__init__.py | bitmath --from-stdin -t MB 0.038374 MB Convert several values at once from Bytes (the default behavior) into MBs: .. code-block:: bash $ bitmath -t MB 1234567 9876543 1337 42 1.234567 MB 9.876543 MB 0.001337 MB 4.2e-05 MB bitmath-1.3.3.1/docsite/source/conf.py000066400000000000000000000200241333755710600175460ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # bitmath documentation build configuration file, created by # sphinx-quickstart on Sun Jul 13 20:40:01 2014. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os try: import sphinx_rtd_theme except ImportError: _RTD_THEME = False pass else: _RTD_THEME = True # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0, os.path.abspath('../../bitmath')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.viewcode', 'sphinx.ext.mathjax'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'bitmath' copyright = u'2014-2016, Tim Bielawa' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '1.3.3' # The full version, including alpha/beta/rc tags. release = '1.3.3' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = [ 'appendices/mixed_math.rst', 'appendices/*', 'example_block_devices.rst', 'query_device_capacity_warning.rst' ] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. if _RTD_THEME: html_theme = "sphinx_rtd_theme" html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] else: html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. html_last_updated_fmt = '%Y-%m-%d - %H:%M:%S %Z' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. html_domain_indices = False # If false, no index is generated. html_use_index = False # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. html_show_sphinx = False # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'bitmathdoc' # -- Options for LaTeX output -------------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'bitmath.tex', u'bitmath Documentation', u'Tim Bielawa', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'bitmath', u'bitmath Documentation', [u'Tim Bielawa'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------------ # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'bitmath', u'bitmath Documentation', u'Tim Bielawa', 'bitmath', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' bitmath-1.3.3.1/docsite/source/conf.py.in000066400000000000000000000200341333755710600201540ustar00rootroot00000000000000# -*- coding: utf-8 -*- # # bitmath documentation build configuration file, created by # sphinx-quickstart on Sun Jul 13 20:40:01 2014. # # This file is execfile()d with the current directory set to its containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import sys, os try: import sphinx_rtd_theme except ImportError: _RTD_THEME = False pass else: _RTD_THEME = True # If extensions (or modules to document with autodoc) are in another directory, # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. sys.path.insert(0, os.path.abspath('../../bitmath')) # -- General configuration ----------------------------------------------------- # If your documentation needs a minimal Sphinx version, state it here. #needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be extensions # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.todo', 'sphinx.ext.coverage', 'sphinx.ext.viewcode', 'sphinx.ext.mathjax'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] # The suffix of source filenames. source_suffix = '.rst' # The encoding of source files. #source_encoding = 'utf-8-sig' # The master toctree document. master_doc = 'index' # General information about the project. project = u'bitmath' copyright = u'2014-2016, Tim Bielawa' # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = '%VERSION%' # The full version, including alpha/beta/rc tags. release = '%VERSION%' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. #language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: #today = '' # Else, today_fmt is used as the format for a strftime call. #today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = [ 'appendices/mixed_math.rst', 'appendices/*', 'example_block_devices.rst', 'query_device_capacity_warning.rst' ] # The reST default role (used for this markup: `text`) to use for all documents. #default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. #add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). #add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. #show_authors = False # The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' # A list of ignored prefixes for module index sorting. #modindex_common_prefix = [] # -- Options for HTML output --------------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. if _RTD_THEME: html_theme = "sphinx_rtd_theme" html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] else: html_theme = 'default' # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. #html_theme_options = {} # Add any paths that contain custom themes here, relative to this directory. #html_theme_path = [] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". #html_title = None # A shorter title for the navigation bar. Default is the same as html_title. #html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. #html_logo = None # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. #html_favicon = None # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". html_static_path = ['_static'] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. html_last_updated_fmt = '%Y-%m-%d - %H:%M:%S %Z' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. #html_use_smartypants = True # Custom sidebar templates, maps document names to template names. #html_sidebars = {} # Additional templates that should be rendered to pages, maps page names to # template names. #html_additional_pages = {} # If false, no module index is generated. html_domain_indices = False # If false, no index is generated. html_use_index = False # If true, the index is split into individual pages for each letter. #html_split_index = False # If true, links to the reST sources are added to the pages. html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. html_show_sphinx = False # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. #html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. #html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). #html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = 'bitmathdoc' # -- Options for LaTeX output -------------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). #'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). #'pointsize': '10pt', # Additional stuff for the LaTeX preamble. #'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, author, documentclass [howto/manual]). latex_documents = [ ('index', 'bitmath.tex', u'bitmath Documentation', u'Tim Bielawa', 'manual'), ] # The name of an image file (relative to this directory) to place at the top of # the title page. #latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. #latex_use_parts = False # If true, show page references after internal links. #latex_show_pagerefs = False # If true, show URL addresses after external links. #latex_show_urls = False # Documents to append as an appendix to all manuals. #latex_appendices = [] # If false, no module index is generated. #latex_domain_indices = True # -- Options for manual page output -------------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [ ('index', 'bitmath', u'bitmath Documentation', [u'Tim Bielawa'], 1) ] # If true, show URL addresses after external links. #man_show_urls = False # -- Options for Texinfo output ------------------------------------------------ # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ('index', 'bitmath', u'bitmath Documentation', u'Tim Bielawa', 'bitmath', 'One line description of project.', 'Miscellaneous'), ] # Documents to append as an appendix to all manuals. #texinfo_appendices = [] # If false, no module index is generated. #texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. #texinfo_show_urls = 'footnote' bitmath-1.3.3.1/docsite/source/contact.rst000066400000000000000000000030171333755710600204370ustar00rootroot00000000000000.. _contact: Contact ####### Hi, I'm Tim Bielawa, the bitmath maintainer. Would you like to get in touch? Maybe you want to peek at other stuff I'm working on? Go right ahead: **Blog** I maintain a blog which mostly covers technical problems I encounter that I think are interesting and how I solved them. Lots of rich commentary and details included! * `Technitribe `_ **Open Source** Almost every project I work on, code or not, ends up on GitHub eventually. You can see what else I've been busy with on my profile. * `GitHub: tbielawa `_ **Tweet-Tweet** I have been known to tweet from time to time. * `@tbielawa `_ **Bugs/Issues/Requests** All contributions related directly to the bitmath project, i.e. bug reports or feature requests, should be posted to the project issue tracker on GitHub. Please see the Contributing section for more information. * :ref:`Contributing ` **Saying hello** I'm on the `freenode `_ IRC network Monday through Friday, from around 9am EST through 5pm EST. * Issue a ``/who tbielawa*`` command to the server, a handle with the netmask ``~tbielawa@redhat/tbielawa`` will appear for you to ``/query`` if I'm online. **E-Mail** If you want to contact me directly, `clone the project `_ and look at any of `my bitmath commits `_ to find my email address. bitmath-1.3.3.1/docsite/source/contributing.rst000066400000000000000000000216451333755710600215220ustar00rootroot00000000000000.. _contributing: Contributing to bitmath ####################### This section describes the guidelines for contributing to bitmath. .. contents:: :depth: 3 :local: .. _contributing_issue_reporting: Issue Reporting *************** If you are encounter an issue with the bitmath library, please use the provided template. * `Open a new issue `_ * `View open issues `_ Code Style/Formatting ********************* Please conform to :pep:`0008` for code formatting. This specification outlines the style that is required for patches. Your code must follow this (or note why it can't) before patches will be accepted. There is one consistent exception to this rule: **E501** Line too long The ``pycodestyle`` tests for bitmath include a ``--ignore`` option to automatically exclude **E501** errors from the tests. Commit Messages *************** Please write `intelligent commit messages `_. For example:: Capitalized, short (50 chars or less) summary More detailed explanatory text, if necessary. Wrap it to about 72 characters or so. In some contexts, the first line is treated as the subject of an email and the rest of the text as the body. The blank line separating the summary from the body is critical (unless you omit the body entirely); tools like rebase can get confused if you run the two together. Write your commit message in the imperative: "Fix bug" and not "Fixed bug" or "Fixes bug." This convention matches up with commit messages generated by commands like git merge and git revert. Further paragraphs come after blank lines. - Bullet points are okay, too - Typically a hyphen or asterisk is used for the bullet, followed by a single space, with blank lines in between, but conventions vary here - Use a hanging indent Pull Requests ************* After a `pull request `_ is submitted on GitHub two automatic processes are started: #. `Travis-CI `_ clones the new pull request and runs the :ref:`automated test suite `. #. `Coveralls `_ clones the new pull request and determines if the request would increase or decrease the overall code test coverage. Please check back shortly after submitting a pull request to verify that the Travis-CI process passes. What Happens If The Build Breaks ================================ Pull requests which break the build will be looked at closely and you may be asked to fix the tests. The bitmath project **welcomes all contributors** so **it's OK** if you're unable to fix the tests yourself. Just leave a comment in the pull request explaining so if that is the case. Likewise, if Coveralls indicates the pull request would decrease the overall test-coverage, and you aren't able to fix it yourself, just leave a comment in the pull request. .. _contributing_automated_tests: Automated Tests *************** Write `unittests `_ for any new functionality, `if you are up to the task`. This is not a requirement, but it does get you a lot of karma. All bitmath code includes unit tests to verify expected functionality. In the rest of this section we'll learn how the unit tests are put together and how to interact with them. Components ========== bitmath unit tests are integrated with/depend on the following items: * `Travis CI `_ - Free online service providing `continuous integration` functionality for open source projects. Tests are ran automatically on every git commit. Integrates with GitHub to notify you if a pull request passes or fails all unitests. * `Coveralls `_ - Free online service providing code test coverage reporting. Integrates with GitHub to notify you if a pull-request would improve/decrease overall code test coverage. * `unittest `_ - Python unit testing framework. All bitmath tests are written using this framework. * `nose `_ - Per the **nose** website: "`extends unittest to make testing easier`". **nose** is used to run our unit tests. * `coverage `_ - A tool for measuring code coverage of Python programs. For bitmath we require a minimum test coverage of **90%**. This is invoked by **nose** automatically. * `pycodestyle `_ - A tool to check Python code against some of the style conventions in :pep:`0008`. * `pyflakes `_ - A simple program which checks Python source files for errors. * `virtualenv `_ - A tool to create isolated Python environments. Allows us to install additional package dependencies without requiring access to the system site-packages directory. * `Makefiles `_ - Utility scripts used for project building and testing. How bitmath uses **Makefiles** is described later in this section. Targets ======= In the scope of this document, we use the term `target` in the context of `makefile targets`. For the purpose of this documentation, we can think of these `targets` as pre-defined commands coded in a makefile. bitmath testing targets include: * ``ci`` - Run the tests exactly how they are ran in Travis-CI. The ``ci`` target automatically calls the ``pycodestyle``, ``pyflakes``, ``uniquetestnames``, and ``unittests`` targets. * ``ci3`` - Is the same as the ``ci`` target, except it runs using the Python 3.x interpreter. * ``unittests`` - Run the functional test suite. * ``pycodestyle`` - Run :pep:`0008` syntax checks. * ``pyflakes`` - Run `pyflakes` error checks. * ``clean`` - Remove temporary files and build artifacts from the checked-out repository. * ``uniquetestnames`` - Ensures no unit tests have the same name. * ``tests`` - A quicker version of ``ci``. Different from ``ci`` in that ``tests`` uses libraries installed on the local development workstation. ``tests`` runs the ``unittests``, ``pycodestyle``, ``uniquetestnames``, and ``pyflakes`` tests automatically. To ensure the highest degree of confidence in test results you should **always use** the ``ci`` and ``ci3`` targets. When Travis-CI runs an integration test, it calls the ``ci`` and ``ci3`` targets. Running the Tests ================= The bitmath test suite is invoked via the Makefile. The following is an example of how to run the ``ci`` test target manually: .. code-block:: console :linenos: :emphasize-lines: 2 [~/Projects/bitmath] 17:22:21 (master) $ make ci ############################################# # Running Unique TestCase checker ############################################# ./tests/test_unique_testcase_names.sh ############################################# # Creating a virtualenv ############################################# virtualenv bitmathenv New python executable in bitmathenv/bin/python Installing setuptools, pip...done. . bitmathenv/bin/activate && pip install -r requirements.txt Downloading/unpacking python-coveralls (from -r requirements.txt (line 1)) Downloading python_coveralls-2.4.3-py2.py3-none-any.whl Downloading/unpacking nose (from -r requirements.txt (line 2)) ... snip ... Convert a bitmath GiB into a Tb ... ok Convert a bitmath PiB into a TiB ... ok Convert a bitmath GiB into a Tib ... ok Convert to kb ... ok Convert a bitmath Bit into a MiB ... ok bitmath type converted to the same unit is properly converted ... ok float(bitmath) returns a float ... ok int(bitmath) returns an int ... ok long(bitmath) returns a long ... ok Name Stmts Miss Cover Missing --------------------------------------- bitmath 440 1 99% 1152 ---------------------------------------------------------------------- Ran 163 tests in 0.035s OK : On line **2** we see how to call a makefile target. In this case it's quite straightforward: ``make ci``. Other targets are called in the same way. For example, to run the ``clean`` target, you run the command ``make clean``. To run the Python 3.x test suite, you would run the command ``make ci3``. Troubleshooting =============== If you find yourself unable to run the unit tests: #. `Search `_ for relevant error messages #. **Read** the error message closely. The solution could be hidden in the error message output. The problem could be as simple as a missing dependency #. If you are unable to figure out all the necessary dependencies to run the tests, file an issue on that specific projects GitHub issue tracker. Include the full error message. bitmath-1.3.3.1/docsite/source/copyright.rst000066400000000000000000000021451333755710600210150ustar00rootroot00000000000000Copyright ######### The MIT License (MIT) Copyright © 2014-2016 Tim Bielawa Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. bitmath-1.3.3.1/docsite/source/example_block_devices.rst000066400000000000000000000002651333755710600233150ustar00rootroot00000000000000Examples of supported devices include: * Standard Hard Drives/External Drives * Filesystem Partitions * Loop Devices * LVM Logical Volumes * Encrypted LUKS Volumes * iSCSI Devices bitmath-1.3.3.1/docsite/source/index.rst000066400000000000000000000277711333755710600201300ustar00rootroot00000000000000.. image:: https://api.travis-ci.org/tbielawa/bitmath.png :target: https://travis-ci.org/tbielawa/bitmath/ :align: right :height: 19 :width: 77 .. image:: https://coveralls.io/repos/tbielawa/bitmath/badge.png?branch=master :target: https://coveralls.io/github/tbielawa/bitmath :align: right :height: 19 :width: 77 bitmath ####### `bitmath `_ simplifies many facets of interacting with file sizes in various units. Originally focusing on file size unit conversion, functionality now includes: * Converting between **SI** and **NIST** prefix units (``kB`` to ``GiB``) * Converting between units of the same type (SI to SI, or NIST to NIST) * Automatic human-readable prefix selection (like in `hurry.filesize `_) * Basic arithmetic operations (subtracting 42KiB from 50GiB) * Rich comparison operations (``1024 Bytes == 1KiB``) * bitwise operations (``<<``, ``>>``, ``&``, ``|``, ``^``) * Reading a device's storage capacity (Linux/OS X support only) * `argparse `_ integration as a custom type * `progressbar `_ integration as a better file transfer speed widget * String parsing * Sorting In addition to the conversion and math operations, `bitmath` provides human readable representations of values which are suitable for use in interactive shells as well as larger scripts and applications. The format produced for these representations is customizable via the functionality included in stdlibs `string.format `_. In discussion we will refer to the NIST units primarily. I.e., instead of "megabyte" we will refer to "mebibyte". The former is ``10^3 = 1,000,000`` bytes, whereas the second is ``2^20 = 1,048,576`` bytes. When you see file sizes or transfer rates in your web browser, most of the time what you're really seeing are the base-2 sizes/rates. **Don't Forget!** The source for bitmath `is available on GitHub `_. And did we mention there's almost 200 unittests? `Check them out for yourself `_. * :ref:`Examples ` after the TOC. Installation ############ The easiest way to install bitmath is via ``dnf`` (or ``yum``) if you're on a Fedora/RHEL based distribution. bitmath is available in the main Fedora repositories, as well as the EPEL6 and EPEL7 repositories. There are now dual python2.x and python3.x releases available. **Python 2.x**: .. code-block:: bash $ sudo dnf install python2-bitmath **Python 3.x**: .. code-block:: bash $ sudo dnf install python3-bitmath .. note:: **Upgrading**: If you have the old *python-bitmath* package installed presently, you could also run ``sudo dnf update python-bitmath`` instead **PyPi**: You could also install bitmath from `PyPi `_ if you like: .. code-block:: bash $ sudo pip install bitmath .. note:: **pip** installs need pip >= 1.1. To workaround this, `download bitmath `_, from PyPi and then ``pip install bitmath-x.y.z.tar.gz``. See `issue #57 `_ for more information. **PPA**: Ubuntu Xenial, Wily, Vivid, Trusty, and Precise users can install bitmath from the `launchpad PPA `_: .. code-block:: bash $ sudo add-apt-repository ppa:tbielawa/bitmath $ sudo apt-get update $ sudo apt-get install python-bitmath **Source**: Or, if you want to install from source: .. code-block:: bash $ sudo python ./setup.py install If you want the bitmath manpage installed as well: .. code-block:: bash $ sudo make install Contents ######## .. toctree:: :maxdepth: 2 :numbered: module.rst commandline.rst classes.rst instances.rst simple_examples.rst real_life_examples.rst contributing.rst appendices.rst NEWS.rst contact.rst copyright.rst .. _index_examples: Examples ======== Arithmetic ---------- .. code-block:: python >>> import bitmath >>> log_size = bitmath.kB(137.4) >>> log_zipped_size = bitmath.Byte(987) >>> print "Compression saved %s space" % (log_size - log_zipped_size) Compression saved 136.413kB space >>> thumb_drive = bitmath.GiB(12) >>> song_size = bitmath.MiB(5) >>> songs_per_drive = thumb_drive / song_size >>> print songs_per_drive 2457.6 Convert Units ------------- File size unit conversion: .. code-block:: python >>> from bitmath import * >>> dvd_size = GiB(4.7) >>> print "DVD Size in MiB: %s" % dvd_size.to_MiB() DVD Size in MiB: 4812.8 MiB Select a human-readable unit ---------------------------- .. code-block:: python >>> small_number = kB(100) >>> ugly_number = small_number.to_TiB() >>> print ugly_number 9.09494701773e-08 TiB >>> print ugly_number.best_prefix() 97.65625 KiB Rich Comparison --------------- .. code-block:: python >>> cd_size = MiB(700) >>> cd_size > dvd_size False >>> cd_size < dvd_size True >>> MiB(1) == KiB(1024) True >>> MiB(1) <= KiB(1024) True Sorting ------- .. code-block:: python >>> sizes = [KiB(7337.0), KiB(1441.0), KiB(2126.0), KiB(2178.0), KiB(2326.0), KiB(4003.0), KiB(48.0), KiB(1770.0), KiB(7892.0), KiB(4190.0)] >>> print sorted(sizes) [KiB(48.0), KiB(1441.0), KiB(1770.0), KiB(2126.0), KiB(2178.0), KiB(2326.0), KiB(4003.0), KiB(4190.0), KiB(7337.0), KiB(7892.0)] Custom Formatting ----------------- * Use of the custom formatting system * All of the available instance properties Example: .. code-block:: python >>> longer_format = """Formatting attributes for %s ...: This instances prefix unit is {unit}, which is a {system} type unit ...: The unit value is {value} ...: This value can be truncated to just 1 digit of precision: {value:.1f} ...: In binary this looks like: {binary} ...: The prefix unit is derived from a base of {base} ...: Which is raised to the power {power} ...: There are {bytes} bytes in this instance ...: The instance is {bits} bits large ...: bytes/bits without trailing decimals: {bytes:.0f}/{bits:.0f}""" % str(ugly_number) >>> print ugly_number.format(longer_format) Formatting attributes for 5.96046447754 MiB This instances prefix unit is MiB, which is a NIST type unit The unit value is 5.96046447754 This value can be truncated to just 1 digit of precision: 6.0 In binary this looks like: 0b10111110101111000010000000 The prefix unit is derived from a base of 2 Which is raised to the power 20 There are 6250000.0 bytes in this instance The instance is 50000000.0 bits large bytes/bits without trailing decimals: 6250000/50000000 Utility Functions ----------------- **bitmath.getsize()** .. code-block:: python >>> print bitmath.getsize('python-bitmath.spec') 3.7060546875 KiB **bitmath.parse_string()** Parse a string with standard units: .. code-block:: python >>> import bitmath >>> a_dvd = bitmath.parse_string("4.7 GiB") >>> print type(a_dvd) >>> print a_dvd 4.7 GiB **bitmath.parse_string_unsafe()** Parse a string with ambiguous units: .. code-block:: python >>> import bitmath >>> a_gig = bitmath.parse_string_unsafe("1gb") >>> print type(a_gig) >>> a_gig == bitmath.GB(1) True >>> bitmath.parse_string_unsafe('1gb') == bitmath.parse_string_unsafe('1g') True **bitmath.query_device_capacity()** .. code-block:: python >>> import bitmath >>> with open('/dev/sda') as fp: ... root_disk = bitmath.query_device_capacity(fp) ... print root_disk.best_prefix() ... 238.474937439 GiB **bitmath.listdir()** .. code-block:: python >>> for i in bitmath.listdir('./tests/', followlinks=True, relpath=True, bestprefix=True): ... print i ... ('tests/test_file_size.py', KiB(9.2900390625)) ('tests/test_basic_math.py', KiB(7.1767578125)) ('tests/__init__.py', KiB(1.974609375)) ('tests/test_bitwise_operations.py', KiB(2.6376953125)) ('tests/test_context_manager.py', KiB(3.7744140625)) ('tests/test_representation.py', KiB(5.2568359375)) ('tests/test_properties.py', KiB(2.03125)) ('tests/test_instantiating.py', KiB(3.4580078125)) ('tests/test_future_math.py', KiB(2.2001953125)) ('tests/test_best_prefix_BASE.py', KiB(2.1044921875)) ('tests/test_rich_comparison.py', KiB(3.9423828125)) ('tests/test_best_prefix_NIST.py', KiB(5.431640625)) ('tests/test_unique_testcase_names.sh', Byte(311.0)) ('tests/.coverage', KiB(3.1708984375)) ('tests/test_best_prefix_SI.py', KiB(5.34375)) ('tests/test_to_built_in_conversion.py', KiB(1.798828125)) ('tests/test_to_Type_conversion.py', KiB(8.0185546875)) ('tests/test_sorting.py', KiB(4.2197265625)) ('tests/listdir_symlinks/10_byte_file_link', Byte(10.0)) ('tests/listdir_symlinks/depth1/depth2/10_byte_file', Byte(10.0)) ('tests/listdir_nosymlinks/depth1/depth2/10_byte_file', Byte(10.0)) ('tests/listdir_nosymlinks/depth1/depth2/1024_byte_file', KiB(1.0)) ('tests/file_sizes/kbytes.test', KiB(1.0)) ('tests/file_sizes/bytes.test', Byte(38.0)) ('tests/listdir/10_byte_file', Byte(10.0)) Formatting ---------- .. code-block:: python >>> with bitmath.format(fmt_str="[{value:.3f}@{unit}]"): ... for i in bitmath.listdir('./tests/', followlinks=True, relpath=True, bestprefix=True): ... print i[1] ... [9.290@KiB] [7.177@KiB] [1.975@KiB] [2.638@KiB] [3.774@KiB] [5.257@KiB] [2.031@KiB] [3.458@KiB] [2.200@KiB] [2.104@KiB] [3.942@KiB] [5.432@KiB] [311.000@Byte] [3.171@KiB] [5.344@KiB] [1.799@KiB] [8.019@KiB] [4.220@KiB] [10.000@Byte] [10.000@Byte] [10.000@Byte] [1.000@KiB] [1.000@KiB] [38.000@Byte] [10.000@Byte] ``argparse`` Integration ------------------------ Example script using ``bitmath.integrations.BitmathType`` as an argparser argument type: .. code-block:: python import argparse import bitmath parser = argparse.ArgumentParser( description="Arg parser with a bitmath type argument") parser.add_argument('--block-size', type=bitmath.integrations.BitmathType, required=True) results = parser.parse_args() print "Parsed in: {PARSED}; Which looks like {TOKIB} as a Kibibit".format( PARSED=results.block_size, TOKIB=results.block_size.Kib) If ran as a script the results would be similar to this: .. code-block:: bash $ python ./bmargparse.py --block-size 100MiB Parsed in: 100.0 MiB; Which looks like 819200.0 Kib as a Kibibit ``progressbar`` Integration --------------------------- Use ``bitmath.integrations.BitmathFileTransferSpeed`` as a ``progressbar`` file transfer speed widget to monitor download speeds: .. code-block:: python import requests import progressbar import bitmath import bitmath.integrations FETCH = 'https://www.kernel.org/pub/linux/kernel/v3.0/patch-3.16.gz' widgets = ['Bitmath Progress Bar Demo: ', ' ', progressbar.Bar(marker=progressbar.RotatingMarker()), ' ', bitmath.integrations.BitmathFileTransferSpeed()] r = requests.get(FETCH, stream=True) size = bitmath.Byte(int(r.headers['Content-Length'])) pbar = progressbar.ProgressBar(widgets=widgets, maxval=int(size), term_width=80).start() chunk_size = 2048 with open('/dev/null', 'wb') as fd: for chunk in r.iter_content(chunk_size): fd.write(chunk) if (pbar.currval + chunk_size) < pbar.maxval: pbar.update(pbar.currval + chunk_size) pbar.finish() If ran as a script the results would be similar to this: .. code-block:: bash $ python ./smalldl.py Bitmath Progress Bar Demo: ||||||||||||||||||||||||||||||||||||||||| 1.58 MiB/s bitmath-1.3.3.1/docsite/source/index.rst.in000066400000000000000000000102131333755710600205140ustar00rootroot00000000000000.. image:: https://api.travis-ci.org/tbielawa/bitmath.png :target: https://travis-ci.org/tbielawa/bitmath/ :align: right :height: 19 :width: 77 .. image:: https://coveralls.io/repos/tbielawa/bitmath/badge.png?branch=master :target: https://coveralls.io/github/tbielawa/bitmath :align: right :height: 19 :width: 77 bitmath ####### `bitmath `_ simplifies many facets of interacting with file sizes in various units. Originally focusing on file size unit conversion, functionality now includes: * Converting between **SI** and **NIST** prefix units (``kB`` to ``GiB``) * Converting between units of the same type (SI to SI, or NIST to NIST) * Automatic human-readable prefix selection (like in `hurry.filesize `_) * Basic arithmetic operations (subtracting 42KiB from 50GiB) * Rich comparison operations (``1024 Bytes == 1KiB``) * bitwise operations (``<<``, ``>>``, ``&``, ``|``, ``^``) * Reading a device's storage capacity (Linux/OS X support only) * `argparse `_ integration as a custom type * `progressbar `_ integration as a better file transfer speed widget * String parsing * Sorting In addition to the conversion and math operations, `bitmath` provides human readable representations of values which are suitable for use in interactive shells as well as larger scripts and applications. The format produced for these representations is customizable via the functionality included in stdlibs `string.format `_. In discussion we will refer to the NIST units primarily. I.e., instead of "megabyte" we will refer to "mebibyte". The former is ``10^3 = 1,000,000`` bytes, whereas the second is ``2^20 = 1,048,576`` bytes. When you see file sizes or transfer rates in your web browser, most of the time what you're really seeing are the base-2 sizes/rates. **Don't Forget!** The source for bitmath `is available on GitHub `_. And did we mention there's almost 200 unittests? `Check them out for yourself `_. * :ref:`Examples ` after the TOC. Installation ############ The easiest way to install bitmath is via ``dnf`` (or ``yum``) if you're on a Fedora/RHEL based distribution. bitmath is available in the main Fedora repositories, as well as the EPEL6 and EPEL7 repositories. There are now dual python2.x and python3.x releases available. **Python 2.x**: .. code-block:: bash $ sudo dnf install python2-bitmath **Python 3.x**: .. code-block:: bash $ sudo dnf install python3-bitmath .. note:: **Upgrading**: If you have the old *python-bitmath* package installed presently, you could also run ``sudo dnf update python-bitmath`` instead **PyPi**: You could also install bitmath from `PyPi `_ if you like: .. code-block:: bash $ sudo pip install bitmath .. note:: **pip** installs need pip >= 1.1. To workaround this, `download bitmath `_, from PyPi and then ``pip install bitmath-x.y.z.tar.gz``. See `issue #57 `_ for more information. **PPA**: Ubuntu Xenial, Wily, Vivid, Trusty, and Precise users can install bitmath from the `launchpad PPA `_: .. code-block:: bash $ sudo add-apt-repository ppa:tbielawa/bitmath $ sudo apt-get update $ sudo apt-get install python-bitmath **Source**: Or, if you want to install from source: .. code-block:: bash $ sudo python ./setup.py install If you want the bitmath manpage installed as well: .. code-block:: bash $ sudo make install Contents ######## .. toctree:: :maxdepth: 2 :numbered: module.rst commandline.rst classes.rst instances.rst simple_examples.rst real_life_examples.rst contributing.rst appendices.rst NEWS.rst contact.rst copyright.rst .. _index_examples: bitmath-1.3.3.1/docsite/source/instances.rst000066400000000000000000000275521333755710600210050ustar00rootroot00000000000000Instances ######### .. _instance_attributes: .. contents:: :depth: 3 :local: .. _instances_attributes: Instance Attributes ******************* bitmath objects have several instance attributes: .. py:attribute:: BitMathInstance.base The mathematical base of the unit of the instance (this will be **2** or **10**) .. code-block:: python >>> b = bitmath.Byte(1337) >>> print b.base 2 .. py:attribute:: BitMathInstance.binary The `Python binary representation `_ of the instance's value (in bits) .. code-block:: python >>> b = bitmath.Byte(1337) >>> print b.binary 0b10100111001000 .. py:attribute:: BitMathInstance.bin This is an alias for ``binary`` .. py:attribute:: BitMathInstance.bits The number of bits in the object .. code-block:: python >>> b = bitmath.Byte(1337) >>> print b.bits 10696.0 .. py:attribute:: BitMathInstance.bytes The number of bytes in the object .. code-block:: python >>> b = bitmath.Byte(1337) >>> print b.bytes 1337 .. py:attribute:: BitMathInstance.power The mathematical power the ``base`` of the unit of the instance is raised to .. code-block:: python >>> b = bitmath.Byte(1337) >>> print b.power 0 .. py:attribute:: BitMathInstance.system The system of units used to measure this instance (``NIST`` or ``SI``) .. code-block:: python >>> b = bitmath.Byte(1337) >>> print b.system NIST .. py:attribute:: BitMathInstance.value The value of the instance in *prefix* units\ :sup:`1` .. code-block:: python >>> b = bitmath.Byte(1337) >>> print b.value 1337.0 .. py:attribute:: BitMathInstance.unit The string representation of this prefix unit (such as ``MiB`` or ``kb``) .. code-block:: python >>> b = bitmath.Byte(1337) >>> print b.unit Byte .. py:attribute:: BitMathInstance.unit_plural The pluralized string representation of this prefix unit. .. code-block:: python >>> b = bitmath.Byte(1337) >>> print b.unit_plural Bytes .. py:attribute:: BitMathInstance.unit_singular The singular string representation of this prefix unit (such as ``MiB`` or ``kb``) .. code-block:: python >>> b = bitmath.Byte(1337) >>> print b.unit_singular Byte **Notes:** 1. Given an instance ``k``, where ``k = KiB(1.3)``, then ``k.value`` is **1.3** ---- The following is an example of how to access some of these attributes and what you can expect their printed representation to look like: .. code-block:: python :linenos: >>> dvd_capacity = GB(4.7) >>> print "Capacity in bits: %s\nbytes: %s\n" % \ (dvd_capacity.bits, dvd_capacity.bytes) Capacity in bits: 37600000000.0 bytes: 4700000000.0 >>> dvd_capacity.value 4.7 >>> dvd_capacity.bin '0b100011000001001000100111100000000000' >>> dvd_capacity.binary '0b100011000001001000100111100000000000' Instance Methods **************** bitmath objects come with a few basic methods: :py:meth:`to_THING`, :py:meth:`format`, and :py:meth:`best_prefix`. .. _instances_to_thing: to_THING() ========== Like the :ref:`available classes `, there are 24 ``to_THING()`` methods available. ``THING`` is any of the bitmath classes. You can even ``to_THING()`` an instance into itself again: .. code-block:: python :linenos: :emphasize-lines: 3,7,12 >>> from bitmath import * >>> one_mib = MiB(1) >>> one_mib_in_kb = one_mib.to_kb() >>> one_mib == one_mib_in_kb True >>> another_mib = one_mib.to_MiB() >>> print one_mib, one_mib_in_kb, another_mib 1.0 MiB 8388.608 kb 1.0 MiB >>> six_TB = TB(6) >>> six_TB_in_bits = six_TB.to_Bit() >>> print six_TB, six_TB_in_bits 6.0 TB 4.8e+13 Bit >>> six_TB == six_TB_in_bits True .. _instances_best_prefix: best_prefix() ============= .. py:method:: best_prefix([system=None]) Return an equivalent instance which uses the best human-readable prefix-unit to represent it. :param int system: one of :py:const:`bitmath.NIST` or :py:const:`bitmath.SI` :return: An equivalent :py:class:`bitmath` instance :rtype: :py:class:`bitmath` :raises ValueError: if an invalid unit system is given for ``system`` The :py:meth:`best_prefix` method returns the result of converting a bitmath instance into an equivalent instance using a prefix unit that better represents the original value. Another way to think of this is automatic discovery of the most sane, or *human readable*, unit to represent a given size. This functionality is especially important in the domain of interactive applications which need to report file sizes or transfer rates to users. As an analog, consider you have 923,874,434¢ in your bank account. You probably wouldn't want to read your bank statement and find your balance in pennies. Most likely, your bank statement would read a balance of $9,238,744.34. In this example, the input prefix is the *cent*: ``¢``. The *best prefix* for this is the *dollar*: ``$``. Let's, for example, say we are reporting a transfer rate in an interactive application. It's important to present this information in an easily consumable format. The library we're using to calculate the rate of transfer reports the rate in bytes per second from a :py:func:`tx_rate` function. We'll use this example twice. In the first occurrence, we will print out the transfer rate in a more easily digestible format than pure bytes/second. In the second occurrence we'll take it a step further, and use the :ref:`format ` method to make the output even easier to read. .. code-block:: python >>> for _rate in tx_rate(): ... print "Rate: %s/second" % Bit(_rate) ... time.sleep(1) Rate: 100.0 Bit/sec Rate: 24000.0 Bit/sec Rate: 1024.0 Bit/sec Rate: 60151.0 Bit/sec Rate: 33.0 Bit/sec Rate: 9999.0 Bit/sec Rate: 9238742.0 Bit/sec Rate: 2.09895849555e+13 Bit/sec Rate: 934098021.0 Bit/sec Rate: 934894.0 Bit/sec And now using a custom formatting definition: .. code-block:: python >>> for _rate in tx_rate(): ... print Bit(_rate).best_prefix().format("Rate: {value:.3f} {unit}/sec") ... time.sleep(1) Rate: 12.500 Byte/sec Rate: 2.930 KiB/sec Rate: 128.000 Byte/sec Rate: 7.343 KiB/sec Rate: 4.125 Byte/sec Rate: 1.221 KiB/sec Rate: 1.101 MiB/sec Rate: 2.386 TiB/sec Rate: 111.353 MiB/sec Rate: 114.123 KiB/sec .. _instances_format: format() ======== .. py:method:: BitMathInstance.format(fmt_spec) Return a custom-formatted string to represent this instance. :param str fmt_spec: A valid formatting mini-language string :return: The custom formatted representation :rtype: ``string`` bitmath instances come with a verbose built-in string representation: .. code-block:: python >>> leet_bits = Bit(1337) >>> print leet_bits 1337.0 Bit However, for instances which aren't whole numbers (as in ``MiB(1/3.0) == 0.333333333333 MiB``, etc), their representation can be undesirable. The :py:meth:`format` method gives you complete control over the instance's representation. All of the :ref:`instances attributes ` are available to use when choosing a representation. The following sections describe some common use cases of the :py:meth:`format` method as well as provide a :ref:`brief tutorial ` of the greater Python formatting meta-language. Setting Decimal Precision ------------------------- By default, bitmath instances will print to a fairly long precision for values which are not whole multiples of their prefix unit. In most use cases, simply printing out the first 2 or 3 digits of precision is acceptable. The following examples will show us how to print out a bitmath instance in a more human readable way, by limiting the decimal precision to 2 digits. First, for reference, the default formatting: .. code-block:: python >>> ugly_number = MB(50).to_MiB() / 8.0 >>> print ugly_number 5.96046447754 MiB Now, let's use the :py:meth:`format` method to limit that to two digits of precision: .. code-block:: python >>> print ugly_number.format("{value:.2f}{unit}") 5.96 MiB By changing the **2** character, you increase or decrease the precision. Set it to **0** (``{value:.0f}``) and you have what effectively looks like an integer. Format All the Instance Attributes ---------------------------------- The following example prints out every instance attribute. Take note of how an attribute may be referenced multiple times. .. code-block:: python :linenos: :emphasize-lines: 4,16 >>> longer_format = """Formatting attributes for %s ...: This instances prefix unit is {unit}, which is a {system} type unit ...: The unit value is {value} ...: This value can be truncated to just 1 digit of precision: {value:.1f} ...: In binary this looks like: {binary} ...: The prefix unit is derived from a base of {base} ...: Which is raised to the power {power} ...: There are {bytes} bytes in this instance ...: The instance is {bits} bits large ...: bytes/bits without trailing decimals: {bytes:.0f}/{bits:.0f}""" % str(ugly_number) >>> print ugly_number.format(longer_format) Formatting attributes for 5.96046447754 MiB This instances prefix unit is MiB, which is a NIST type unit The unit value is 5.96046447754 This value can be truncated to just 1 digit of precision: 6.0 In binary this looks like: 0b10111110101111000010000000 The prefix unit is derived from a base of 2 Which is raised to the power 20 There are 6250000.0 bytes in this instance The instance is 50000000.0 bits large bytes/bits without trailing decimals: 6250000/50000000 .. note:: On line **4** we print with 1 digit of precision, on line **16** we see the value has been rounded to **6.0** .. _instances_properties: Instance Properties ******************* THING Properties ================ Like the :ref:`available classes `, there are 24 ``THING`` properties available. ``THING`` is any of the bitmath classes. Under the covers these properties call ``to_THING``. .. code-block:: python :linenos: :emphasize-lines: 3,6,10 >>> from bitmath import * >>> one_mib = MiB(1) >>> one_mib == one_mib.kb True >>> print one_mib, one_mib.kb, one_mib.MiB 1.0 MiB 8388.608 kb 1.0 MiB >>> six_TB = TB(6) >>> print six_TB, six_TB.Bit 6.0 TB 4.8e+13 Bit >>> six_TB == six_TB.Bit True .. _instances_mini_language: The Formatting Mini-Language **************************** That is all you begin printing numbers with custom precision. If you want to learn a little bit more about using the formatting mini-language, read on. You may be asking yourself where these ``{value:.2f}`` and ``{unit}`` strings came from. These are part of the `Format Specification Mini-Language `_ which is part of the Python standard library. To be explicitly clear about what's going on here, let's break the first specifier (``{value:.2f}``) down into it's component parts:: {value:.2f} | ||| | |||\---- The "f" says to format this as a floating point type | ||\----- The 2 indicates we want 2 digits of precision (default is 6) | |\------ The '.' character must precede the precision specifier for floats | \------- The : separates the attribute name from the formatting specification \---------- The name of the attribute to print The second specifier (``{unit}``) says to format the ``unit`` attribute as a string (string is the default type when no type is given). .. seealso:: `Python String Format Cookbook `_ `Marcus Kazmierczak’s `_ *excellent* introduction to string formatting bitmath-1.3.3.1/docsite/source/module.rst000066400000000000000000001115011333755710600202670ustar00rootroot00000000000000.. _module: .. py:module:: bitmath The ``bitmath`` Module ###################### .. contents:: :depth: 3 :local: Functions ********* This section describes utility functions included in the :py:mod:`bitmath` module. .. _bitmath_getsize: bitmath.getsize() ================= .. function:: getsize(path[, bestprefix=True[, system=NIST]]) Return a bitmath instance representing the size of a file at any given path. :param string path: The path of a file to read the size of :param bool bestprefix: **Default:** ``True``, the returned instance will be in the best human-readable prefix unit. If set to ``False`` the result is a ``bitmath.Byte`` instance. :param system: **Default:** :py:data:`bitmath.NIST`. The preferred system of units for the returned instance. :type system: One of :py:data:`bitmath.NIST` or :py:data:`bitmath.SI` Internally :py:func:`bitmath.getsize` calls :py:func:`os.path.realpath` before calling :py:func:`os.path.getsize` on any paths. Here's an example of where we'll run :py:func:`bitmath.getsize` on the bitmath source code using the defaults for the ``bestprefix`` and ``system`` parameters: .. code-block:: python >>> import bitmath >>> print bitmath.getsize('./bitmath/__init__.py') 33.3583984375 KiB Let's say we want to see the results in bytes. We can do this by setting ``bestprefix`` to ``False``: .. code-block:: python >>> import bitmath >>> print bitmath.getsize('./bitmath/__init__.py', bestprefix=False) 34159.0 Byte Recall, the default for representation is with the best human-readable prefix. We can control the prefix system used by setting ``system`` to either :py:data:`bitmath.NIST` (the default) or :py:data:`bitmath.SI`: .. code-block:: python :linenos: :emphasize-lines: 1-4 >>> print bitmath.getsize('./bitmath/__init__.py') 33.3583984375 KiB >>> print bitmath.getsize('./bitmath/__init__.py', system=bitmath.NIST) 33.3583984375 KiB >>> print bitmath.getsize('./bitmath/__init__.py', system=bitmath.SI) 34.159 kB We can see in lines **1** → **4** that the same result is returned when ``system`` is not set and when ``system`` is set to :py:data:`bitmath.NIST` (the default). .. versionadded:: 1.0.7 bitmath.listdir() ================= .. function:: listdir(search_base[, followlinks=False[, filter='*'[, relpath=False[, bestprefix=False[, system=NIST]]]]]) This is a `generator `_ which recurses a directory tree yielding 2-tuples of: * The absolute/relative path to a discovered file * A bitmath instance representing the *apparent size* of the file :param string search_base: The directory to begin walking down :param bool followlinks: **Default:** ``False``, do not follow links. Whether or not to follow symbolic links to directories. Setting to ``True`` enables directory link following :param string filter: **Default:** ``*`` (everything). A glob to filter results with. See `fnmatch `_ for more details about *globs* :param bool relpath: **Default:** ``False``, returns the fully qualified to each discovered file. ``True`` to return the relative path from the present working directory to the discovered file. If ``relpath`` is ``False``, then :py:func:`bitmath.listdir` internally calls :py:func:`os.path.realpath` to normalize path references :param bool bestprefix: **Default:** ``False``, returns ``bitmath.Byte`` instances. Set to ``True`` to return the best human-readable prefix unit for representation :param system: **Default:** :py:data:`bitmath.NIST`. Set a prefix preferred unit system. Requires ``bestprefix`` is ``True`` :type system: One of :py:data:`bitmath.NIST` or :py:data:`bitmath.SI` .. note:: * This function does **not** return tuples for directory entities. Including directories in results is `scheduled for introduction `_ in the upcoming 1.1.0 release. * Symlinks to **files** are followed automatically When interpreting the results from this function it is *crucial* to understand exactly which items are being taken into account, what decisions were made to select those items, and how their sizes are measured. Results from this function may seem invalid when directly compared to the results from common command line utilities, such as ``du``, or ``tree``. Let's pretend we have a directory structure like the following:: some_files/ ├── deeper_files/ │   └── second_file └── first_file Where ``some_files/`` is a directory, and so is ``some_files/deeper_files/``. There are two regular files in this tree: * ``somefiles/first_file`` - 1337 Bytes * ``some_files/deeper_files/second_file`` - 13370 Bytes The **total** size of the files in this tree is **1337 + 13370 = 14707** bytes. Let's call :py:func:`bitmath.listdir` on the ``some_files/`` directory and see what the results look like. First we'll use all the default parameters, then we'll set ``relpath`` to ``True``: .. code-block:: python :linenos: :emphasize-lines: 5-6,10-11 >>> import bitmath >>> for f in bitmath.listdir('./some_files'): ... print f ... ('/tmp/tmp.P5lqtyqwPh/some_files/first_file', Byte(1337.0)) ('/tmp/tmp.P5lqtyqwPh/some_files/deeper_files/second_file', Byte(13370.0)) >>> for f in bitmath.listdir('./some_files', relpath=True): ... print f ... ('some_files/first_file', Byte(1337.0)) ('some_files/deeper_files/second_file', Byte(13370.0)) On lines **5** and **6** the results print the full path, whereas on lines **10** and **11** the path is relative to the present working directory. Let's play with the ``filter`` parameter now. Let's say we only want to include results for files whose name begins with "second": .. code-block:: python >>> for f in bitmath.listdir('./some_files', filter='second*'): ... print f ... ('/tmp/tmp.P5lqtyqwPh/some_files/deeper_files/second_file', Byte(13370.0)) If we wish to avoid having to write for-loops, we can collect the results into a list rather simply: .. code-block:: python >>> files = list(bitmath.listdir('./some_files')) >>> print files [('/tmp/tmp.P5lqtyqwPh/some_files/first_file', Byte(1337.0)), ('/tmp/tmp.P5lqtyqwPh/some_files/deeper_files/second_file', Byte(13370.0))] Here's a more advanced example where we will sum the size of all the returned results and then play around with the possible formatting. Recall that a bitmath instance representing the size of the discovered file is the second item in each returned tuple. .. code-block:: python >>> discovered_files = [f[1] for f in bitmath.listdir('./some_files')] >>> print discovered_files [Byte(1337.0), Byte(13370.0)] >>> print reduce(lambda x,y: x+y, discovered_files) 14707.0 Byte >>> print reduce(lambda x,y: x+y, discovered_files).best_prefix() 14.3623046875 KiB >>> print reduce(lambda x,y: x+y, discovered_files).best_prefix().format("{value:.3f} {unit}") 14.362 KiB .. versionadded:: 1.0.7 bitmath.parse_string() ====================== .. function:: parse_string(str_repr) .. versionadded:: 1.1.0 Parse a string representing a unit into a proper bitmath object. All non-string inputs are rejected and will raise a :py:exc:`ValueError`. Strings without units are also rejected. See the examples below for additional clarity. :param string str_repr: The string to parse. May contain whitespace between the value and the unit. :return: A bitmath object representing ``str_repr`` :raises ValueError: if ``str_repr`` can not be parsed A simple usage example: .. code-block:: python >>> import bitmath >>> a_dvd = bitmath.parse_string("4.7 GiB") >>> print type(a_dvd) >>> print a_dvd 4.7 GiB .. caution:: Caution is advised if you are reading values from an unverified external source, such as output from a shell command or a generated file. Many applications (even ``/usr/bin/ls``) still do not produce file size strings with valid (or even correct) prefix units unless `specially configured to do so `_. See :py:func:`bitmath.parse_string_unsafe` as an alternative. To protect your application from unexpected runtime errors it is recommended that calls to :py:func:`bitmath.parse_string` are wrapped in a ``try`` statement: .. code-block:: python >>> import bitmath >>> try: ... a_dvd = bitmath.parse_string("4.7 G") ... except ValueError: ... print "Error while parsing string into bitmath object" ... Error while parsing string into bitmath object Here we can see some more examples of invalid input, as well as two acceptable inputs: .. code-block:: python >>> import bitmath >>> sizes = [ 1337, 1337.7, "1337", "1337.7", "1337 B", "1337B" ] >>> for size in sizes: ... try: ... print "Parsed size into %s" % bitmath.parse_string(size).best_prefix() ... except ValueError: ... print "Could not parse input: %s" % size ... Could not parse input: 1337 Could not parse input: 1337.7 Could not parse input: 1337 Could not parse input: 1337.7 Parsed size into 1.3056640625 KiB Parsed size into 1.3056640625 KiB .. versionchanged:: 1.2.4 Added support for parsing *octet* units via issue `#53 - parse french units `_. The `usage `_ of "octet" is still common in some `RFCs `_, as well as France, French Canada and Romania. See also, a table of the octet units and their values on `Wikipedia `_. Here are some simple examples of parsing *octet* based units: .. code-block:: python :linenos: :emphasize-lines: 4,5 >>> import bitmath >>> a_mebibyte = bitmath.parse_string("1 MiB") >>> a_mebioctet = bitmath.parse_string("1 Mio") >>> print a_mebibyte, a_mebioctet 1.0 MiB 1.0 MiB >>> print bitmath.parse_string("1Po") 1.0 PB >>> print bitmath.parse_string("1337 Eio") 1337.0 EiB Notice how on lines **4** and **5** that the variable ``a_mebibyte`` from the input ``1 MiB`` is exactly equivalent to ``a_mebioctet`` from the different input ``1 Mio``. This is because after :py:mod:`bitmath` parses the octet units the results are normalized into their **standard** NIST/SI equivalents automatically. .. note:: If your input isn't compatible with :py:func:`bitmath.parse_string` you can try using :py:func:`bitmath.parse_string_unsafe` instead. :py:func:`bitmath.parse_string_unsafe` is more forgiving with input. Please read the documentation carefully so you understand the risks you assume using the ``unsafe`` parser. bitmath.parse_string_unsafe() ============================= .. function:: parse_string_unsafe(repr[, system=bitmath.SI]) .. versionadded:: 1.3.1 Parse a string or number into a proper bitmath object. This is the less strict version of the :py:func:`bitmath.parse_string` function. While :py:func:`bitmath.parse_string` only accepts SI and NIST defined unit prefixes, :py:func:`bitmath.parse_string_unsafe` accepts *non-standard* units such as those often displayed in command-line output. Examples following the description. :param repr: The value to parse. May contain whitespace between the value and the unit. :param system: :py:func:`bitmath.parse_string_unsafe` defaults to parsing units as ``SI`` (base-10) units. Set the ``system`` parameter to :py:data:`bitmath.NIST` if you know your input is in ``NIST`` (base-2) format. :return: A bitmath object representing ``repr`` :raises ValueError: if ``repr`` can not be parsed Use of this function comes with several caveats: * All inputs are assumed to be byte-based (as opposed to bit based) * Numerical inputs (those without any units) are assumed to be a number of bytes * Inputs with single letter units (``k``, ``M``, ``G``, etc) are assumed to be SI units (base-10). See the ``system`` parameter description **above** to change this behavior * Inputs with an ``i`` character following the leading letter (``Ki``, ``Mi``, ``Gi``) are assumed to be NIST units (base-2) * Capitalization does not matter What exactly are these *non-standard* units? Generally speaking non-standard units will not include enough information to be able to identify exactly which unit system is being used. This is caused by mis-capitalized characters (capital ``k``'s for SI *kilo* units when they should be lower case), or omitted Byte or Bit suffixes. You can find examples of non-standard units in many common command line functions or parameters. For example: * The ``ls`` command will print out single-letter units when given the ``-h`` option flag * Running ``qemu-img info virtualdisk.img`` will also report with single letter units * The ``df`` command also uses single-letter units * `Kubernetes `_ will display items like *memory limits* using two letter NIST units (ex: ``memory: 2370Mi``) Given those considerations, understanding exactly what values you are feeding into this function is crucial to getting accurate results. You can control the output of some commands with various option flags. For example, you could ensure the GNU ``ls`` and ``df`` commands print with SI values by providing the ``--si`` option flag. By default those commands will print out using NIST (base-2) values. In this example let's pretend we're parsing the output of running ``df -H / /boot /home`` on our filesystems. Assume the output is saved into a file called ``/tmp/df-output.txt`` and looks like this:: Filesystem Size Used Avail Use% Mounted on /dev/mapper/luks-ca8d5493-72bb-4691-afe1 107G 64G 38G 63% / /dev/sda1 500M 391M 78M 84% /boot /dev/mapper/vg_deepfryer-lv_home 129G 118G 4.7G 97% /home Now let's read this file, parse the ``Used`` column, and then print out the space used (line **7**): .. code-block:: python :linenos: :emphasize-lines: 7 >>> with open('/tmp/df-output.txt', 'r') as fp: ... # Skip parsing the 'df' header column ... _ = fp.readline() ... for line in fp.readlines(): ... cols = line.split()[0:4] ... print """Filesystem: %s ... - Used: %s""" % (cols[0], bitmath.parse_string_unsafe(cols[1])) Filesystem: /dev/mapper/luks-ca8d5493-72bb-4691-afe1 - Used: 107.0 GB Filesystem: /dev/sda1 - Used: 500.0 MB Filesystem: /dev/mapper/vg_deepfryer-lv_home - Used: 129.0 GB If we had ran the ``df`` command with the ``-h`` option (instead of ``-H``) we will get base-2 (NIST) output. That would look like this:: Filesystem Size Used Avail Use% Mounted on /dev/mapper/luks-ca8d5493-72bb-4691-afe1 100G 59G 36G 63% / /dev/sda1 477M 373M 75M 84% /boot /dev/mapper/vg_deepfryer-lv_home 120G 110G 4.4G 97% /home Because we switch from ``SI`` output to ``NIST`` output the values displayed are slightly different. **However** they still print using the same prefix unit, ``G``. We can tell :py:func:`bitmath.parse_string_unsafe` that the input is ``NIST`` (base-2) by giving ``bitmath.NIST`` to the ``system`` parameter like this (line **8**): .. code-block:: python :linenos: :emphasize-lines: 8 >>> with open('/tmp/df-output.txt', 'r') as fp: ... # Skip parsing the 'df' header column ... _ = fp.readline() ... for line in fp.readlines(): ... cols = line.split()[0:4] ... print """Filesystem: %s ... - Used: %s""" % (cols[0], ... bitmath.parse_string_unsafe(cols[1], \ ... system=bitmath.NIST)) Filesystem: /dev/mapper/luks-ca8d5493-72bb-4691-afe1 - Used: 100.0 GiB Filesystem: /dev/sda1 - Used: 477.0 MiB Filesystem: /dev/mapper/vg_deepfryer-lv_home - Used: 120.0 GiB The results printed use the proper NIST prefix unit syntax now: Capital **G** followed by a lower-case **i** ending with a capital **B**, ``GiB``. bitmath.query_device_capacity() =============================== .. function:: query_device_capacity(device_fd) Create :class:`bitmath.Byte` instances representing the capacity of a block device. :param file device_fd: An open file handle (``handle = open('/dev/sda')``) of the target device. :return: A :class:`bitmath.Byte` equal to the size of ``device_fd``. :raises ValueError: if file descriptor ``device_fd`` is not of a device type. :raises IOError: * :py:exc:`IOError[13]` - If the effective **uid** of this process does not have access to issue raw commands to block devices. I.e., this process does not have super-user rights. * :py:exc:`IOError[2]` - If the device ``device_fd`` points to does not exist. .. include:: query_device_capacity_warning.rst .. include:: example_block_devices.rst Here's an example using the ``with`` context manager to open a device and print its capacity with the best-human readable prefix (line **3**): .. code-block:: python :linenos: :emphasize-lines: 3 >>> import bitmath >>> with open("/dev/sda") as device: ... size = bitmath.query_device_capacity(device).best_prefix() ... print "Device %s capacity: %s (%s Bytes)" % (device.name, size, size_bytes) Device /dev/sda capacity: 238.474937439 GiB (2.56060514304e+11 Bytes) .. important:: **Platform Notice**: :py:func:`bitmath.query_device_capacity` is only verified to work on **Linux** and **Mac OS X** platforms. To file a bug report, please follow the instructions in the :ref:`contributing section`. .. versionadded:: 1.2.4 .. _module_context_managers: Context Managers **************** This section describes all of the `context managers `_ provided by the bitmath class. .. note:: For a bit of background, a *context manager* (specifically, the ``with`` statement) is a feature of the Python language which is commonly used to: * Decorate, or *wrap*, an arbitrary block of code. I.e., effect a certain condition onto a specific body of code * Automatically *open* and *close* an object which is used in a specific context. I.e., handle set-up and tear-down of objects in the place they are used. .. seealso:: :pep:`343` *The "with" Statement* :pep:`318` *Decorators for Functions and Methods* .. _module_bitmath_format: bitmath.format() ================ .. function:: format([fmt_str=None[, plural=False[, bestprefix=False]]]) The :py:func:`bitmath.format` context manager allows you to specify the string representation of all bitmath instances within a specific block of code. This is effectively equivalent to applying the :ref:`format()` method to an entire region of code. :param str fmt_str: a formatting mini-language compat formatting string. See the :ref:`instance attributes ` for a list of available items. :param bool plural: ``True`` enables printing instances with trailing **s**'s if they're plural. ``False`` (default) prints them as singular (no trailing 's') :param bool bestprefix: ``True`` enables printing instances in their best human-readable representation. ``False``, the default, prints instances using their current prefix unit. .. note:: The ``bestprefix`` parameter is not yet implemented! Let's look at an example of toggling pluralization on and off. First we'll look over a demonstration script (below), and then we'll review the output. .. code-block:: python :linenos: :emphasize-lines: 33-34 import bitmath a_single_bit = bitmath.Bit(1) technically_plural_bytes = bitmath.Byte(0) always_plural_kbs = bitmath.kb(42) formatting_args = { 'not_plural': a_single_bit, 'technically_plural': technically_plural_bytes, 'always_plural': always_plural_kbs } print """None of the following will be pluralized, because that feature is turned off """ test_string = """ One unit of 'Bit': {not_plural} 0 of a unit is typically said pluralized in US English: {technically_plural} several items of a unit will always be pluralized in normal US English speech: {always_plural}""" print test_string.format(**formatting_args) print """ ---------------------------------------------------------------------- """ print """Now, we'll use the bitmath.format() context manager to print the same test string, but with pluralization enabled. """ with bitmath.format(plural=True): print test_string.format(**formatting_args) The context manager is demonstrated in lines **33** → **34**. In these lines we use the :py:func:`bitmath.format` context manager, setting ``plural`` to ``True``, to print the original string again. By doing this we have enabled pluralized string representations (where appropriate). Running this script would have the following output:: None of the following will be pluralized, because that feature is turned off One unit of 'Bit': 1.0 Bit 0 of a unit is typically said pluralized in US English: 0.0 Byte several items of a unit will always be pluralized in normal US English speech: 42.0 kb ---------------------------------------------------------------------- Now, we'll use the bitmath.format() context manager to print the same test string, but with pluralization enabled. One unit of 'Bit': 1.0 Bit 0 of a unit is typically said pluralized in US English: 0.0 Bytes several items of a unit will always be pluralized in normal US English speech: 42.0 kbs Here's a shorter example, where we'll: * Print a string containing bitmath instances using the default formatting (lines **2** → **3**) * Use the context manager to print the instances in scientific notation (lines **4** → **7**) * Print the string one last time to demonstrate how the formatting automatically returns to the default format (lines **8** → **9**) .. code-block:: python :linenos: >>> import bitmath >>> print "Some instances: %s, %s" % (bitmath.KiB(1 / 3.0), bitmath.Bit(512)) Some instances: 0.333333333333 KiB, 512.0 Bit >>> with bitmath.format("{value:e}-{unit}"): ... print "Some instances: %s, %s" % (bitmath.KiB(1 / 3.0), bitmath.Bit(512)) ... Some instances: 3.333333e-01-KiB, 5.120000e+02-Bit >>> print "Some instances: %s, %s" % (bitmath.KiB(1 / 3.0), bitmath.Bit(512)) Some instances: 0.333333333333 KiB, 512.0 Bit .. versionadded:: 1.0.8 .. _module_class_variables: Module Variables **************** This section describes the module-level variables. Some of which are constants and are used for reference. Some of which effect output or behavior. .. versionchanged:: 1.0.7 The formatting strings were not available for manupulate/inspection in earlier versions .. versionadded:: 1.1.1 Prior to this version :py:data:`ALL_UNIT_TYPES` was not defined .. note:: Modifying these variables will change the default representation indefinitely. Use the :py:func:`bitmath.format` context manager to limit changes to a specific block of code. .. _module_format_string: .. py:data:: format_string This is the default string representation of all bitmath instances. The default value is ``{value} {unit}`` which, when evaluated, formats an instance as a floating point number with at least one digit of precision, followed by a character of whitespace, followed by the prefix unit of the instance. For example, given bitmath instances representing the following values: **1337 MiB**, **0.1234567 kb**, and **0 B**, their printed output would look like the following: .. code-block:: python >>> from bitmath import * >>> print MiB(1337), kb(0.1234567), Byte(0) 1337.0 MiB 0.1234567 kb 0.0 Byte We can make these instances print however we want to. Let's wrap each one in square brackets (``[``, ``]``), replace the separating space character with a hyphen (``-``), and limit the precision to just 2 digits: .. code-block:: python >>> import bitmath >>> bitmath.format_string = "[{value:.2f}-{unit}]" >>> print bitmath.MiB(1337), bitmath.kb(0.1234567), bitmath.Byte(0) [1337.00-MiB] [0.12-kb] [0.00-Byte] .. py:data:: format_plural A boolean which controls the pluralization of instances in string representation. The default is ``False``. If we wanted to enable pluralization we could set the :py:data:`format_plural` variable to ``True``. First, let's look at some output using the default singular formatting. .. code-block:: python >>> import bitmath >>> print bitmath.MiB(1337) 1337.0 MiB And now we'll enable pluralization (line **2**): .. code-block:: python :linenos: :emphasize-lines: 2,5 >>> import bitmath >>> bitmath.format_plural = True >>> print bitmath.MiB(1337) 1337.0 MiBs >>> bitmath.format_plural = False >>> print bitmath.MiB(1337) 1337.0 MiB On line **5** we disable pluralization again and then see that the output has no trailing "s" character. .. py:data:: NIST Constant used as an argument to some functions to specify the **NIST** system. .. py:data:: SI Constant used as an argument to some functions to specify the **SI** system. .. py:data:: SI_PREFIXES An array of all of the SI unit prefixes (e.g., ``k``, ``M``, or ``E``) .. py:data:: SI_STEPS .. code-block:: python SI_STEPS = { 'Bit': 1 / 8.0, 'Byte': 1, 'k': 1000, 'M': 1000000, 'G': 1000000000, 'T': 1000000000000, 'P': 1000000000000000, 'E': 1000000000000000000 } .. py:data:: NIST_PREFIXES An array of all of the NIST unit prefixes (e.g., ``Ki``, ``Mi``, or ``Ei``) .. py:data:: NIST_STEPS .. code-block:: python NIST_STEPS = { 'Bit': 1 / 8.0, 'Byte': 1, 'Ki': 1024, 'Mi': 1048576, 'Gi': 1073741824, 'Ti': 1099511627776, 'Pi': 1125899906842624, 'Ei': 1152921504606846976 } .. py:data:: ALL_UNIT_TYPES An array of all combinations of known valid prefix units mixed with both bit and byte suffixes. .. code-block:: python ALL_UNIT_TYPES = ['b', 'B', 'kb', 'kB', 'Mb', 'MB', 'Gb', 'GB', 'Tb', 'TB', 'Pb', 'PB', 'Eb', 'EB', 'Kib', 'KiB', 'Mib', 'MiB', 'Gib', 'GiB', 'Tib', 'TiB', 'Pib', 'PiB', 'Eib', 'EiB'] .. py:module:: bitmath.integrations 3rd Party Module Integrations ***************************** This section describes the various ways in which :py:mod:`bitmath` can be integrated with other 3rd pary modules. To see a full demo of the :mod:`argparse` and :mod:`progressbar` integrations, as well as a comprehensive demonstrations of the full capabilities of the bitmath library, see :ref:`Creating Download Progress Bars ` in the *Real Life Examples* section. .. _bitmath_BitmathType: argparse ======== .. versionadded:: 1.2.0 The `argparse module `_ (part of stdlib) is used to parse command line arguments. By default, parsed options and arguments are turned into strings. However, one useful feature :py:mod:`argparse` provides is the ability to `specify what datatype `_ any given argument or option should be interpreted as. .. function:: BitmathType(bmstring) The :func:`BitmathType` factory creates objects that can be passed to the type argument of `ArgumentParser.add_argument() `_. Arguments that have :func:`BitmathType` objects as their type will automatically parse the command line argument into a matching :ref:`bitmath object `. :param str bmstring: The command-line option to parse into a bitmath object :returns: A bitmath object representing ``bmstring`` :raises ValueError: on any input that :py:func:`bitmath.parse_string` already rejects :raises ValueError: on **unquoted inputs** with whitespace separating the value from the unit (e.g., ``--some-option 10 MiB`` is bad, but ``--some-option '10 MiB'`` is good) Let's take a look at a more in-depth example. A feature found in many command-line utilities is the ability to specify some kind of file size using a string which roughly describes some kind of parameter. For example, let's look at the :program:`du` (disk usage) command. Invoking it as :option:`du -B` allows one to specify a desired block-size scaling factor in printed results. Let's say we wanted to implement a similar mechanism in an application of our own. Except, instead of abbreviating down to ambiguous capital letters, we accept scaling factors as :ref:`properly written values ` with associated units. Such as **10 MiB**, or **1 MB**. To accomplish this, we'll use :py:mod:`argparse` to create an argument parser and add one option to it, ``--block-size``. This option will have a type of :func:`BitmathType` set. .. code-block:: python :linenos: :emphasize-lines: 3,6,7 >>> import argparse, bitmath >>> parser = argparse.ArgumentParser() >>> parser.add_argument('--block-size', type=bitmath.BitmathType) >>> args = "--block-size 1MiB" >>> results = parser.parse_args(args.split()) >>> print type(results.block_size) On line **3** we add the ``--block-size`` option to the parser, explicitly defining it's type as :func:`BitmathType`. In lines **6** and **7** when we parse the provided arguments we find that :py:mod:`argparse` has automatically created a bitmath object for us. If an invalid scaling factor is provided by the user, such as one which does not represent a recognizable unit, the bitmath library will automatically detect this for us and signal to the argument parser that an error has occurred. .. _bitmath_BitmathFileTransferSpeed: progressbar =========== .. versionadded:: 1.2.1 The `progressbar module `_ is typically used to display the progress of a long running task, such as a file transfer operation. The module provides widgets for custom formatting how exactly the 'progress' is displayed. Some examples include: overall percentage complete, estimated time until completion, and an ASCII progress bar which fills as the operation continues. While :mod:`progressbar` already includes a widget suitable for displaying `file transfer rates `_, this widget does not support customizing its presentation, and is limited to only prefix units from the SI system. .. class:: BitmathFileTransferSpeed([system=bitmath.NIST, [format="{value:.2f} {unit}/s"]]) The :class:`BitmathFileTransferSpeed` class is a more functional replacement for the upstream `FileTransferSpeed `_ widget. While both widgets are able to calculate average transfer rates over a period of time, the :class:`BitmathFileTransferSpeed` widget adds new support for `NIST `_ prefix units (the upstream widget only supports SI prefix units). In addition to NIST unit support, :class:`BitmathFileTransferSpeed` enables the user to have **full control** over the look and feel of the displayed rates. :param system: **Default:** :py:data:`bitmath.NIST`. The preferred system of units for the printed rate. :type system: One of :py:data:`bitmath.NIST` or :py:data:`bitmath.SI` :param string format: a formatting mini-language compat formatting string. **Default** ``{value:.2f} {unit}/s`` (e.g., ``13.37 GiB/s``) .. note:: See :ref:`instance attributes ` for a list of available formatting items. See the section on :ref:`formatting bitmath instances ` for more information on this topic. Use :class:`BitmathFileTransferSpeed` exactly like the upstream ``FileTransferSpeed`` widget (example copied and modified from the progressbar project page): .. code-block:: python :linenos: :emphasize-lines: 2,4 >>> from progressbar import ProgressBar, Percentage, Bar, ETA, RotatingMarker >>> from bitmath.integrations import BitmathFileTransferSpeed >>> widgets = ['Something: ', Percentage(), ' ', Bar(marker=RotatingMarker()), ... ' ', ETA(), ' ', BitmathFileTransferSpeed()] >>> pbar = ProgressBar(widgets=widgets, maxval=10000000).start() >>> for i in range(1000000): ... # do something ... pbar.update(10*i+1) >>> pbar.finish() If this was ran from a script we would see output similar to the following:: Something: 100% ||||||||||||||||||||||||||||||||||| Time: 0:00:01 9.27 MiB/s If we wanted behavior identical to :class:`FileTransferSpeed` we would set the ``system`` parameter to :py:data:`bitmath.SI` (line **5** below): .. code-block:: python :linenos: :emphasize-lines: 5 >>> import bitmath >>> # ... >>> widgets = ['Something: ', Percentage(), ' ', Bar(marker=RotatingMarker()), ... ' ', ETA(), ' ', ... BitmathFileTransferSpeed(system=bitmath.SI)] >>> pbar = ProgressBar(widgets=widgets, maxval=10000000).start() >>> # ... If this was ran from a script we would see output similar to the following:: Something: 100% ||||||||||||||||||||||||||||||||||| Time: 0:00:01 9.80 MB/s Note how the only difference is in the displayed unit. The former example produced a rate with a unit of ``MiB`` (a NIST unit) whereas the latter examples unit is ``MB`` (an SI unit). As noted previously, :class:`BitmathFileTransferSpeed` allows for full control over the formatting of the calculated rate of transfer. For example, if we wished to see the rate printed using more verbose language and plauralized units, we could do exactly that by constructing our widget in the following way: .. code-block:: python BitmathFileTransferSpeed(format="{value:.2f} {unit_plural} per second") And if this were run from a script like the previous examples:: Something: 100% ||||||||||||||||||||||||||||||||||| Time: 0:00:01 9.41 MiBs per second bitmath-1.3.3.1/docsite/source/query_device_capacity_warning.rst000066400000000000000000000004741333755710600250760ustar00rootroot00000000000000.. important:: Superuser (root/admin) privileges are required to allow :func:`bitmath.query_device_capacity` to make system calls to read a devices capacity. Use of this function on a device the user does not have access to will result in run-time errors. bitmath-1.3.3.1/docsite/source/real_life_examples.rst000066400000000000000000000265501333755710600226330ustar00rootroot00000000000000.. highlight:: python .. _real_life_examples: Real Life Examples ################## .. contents:: :depth: 3 :local: Download Speeds *************** Let's pretend that your Internet service provider (ISP) advertises your maximum downstream as **50Mbps** (50 Mega\ **bits** per second)\ :sup:`1` and you want to know how fast that is in Mega\ **bytes** per second? ``bitmath`` can do that for you easily. We can calculate this as such: .. code-block:: python :linenos: >>> import bitmath >>> downstream = bitmath.Mib(50) >>> print downstream.to_MB() MB(6.25) This tells us that if our ISP advertises **50Mbps** we can expect to see download rates of over **6MB/sec**. 1. *Assuming your ISP follows the common industry practice of using SI (base-10) units to describe file sizes/rates* Calculating how many files fit on a device ****************************************** In 2001 Apple® announced the iPod™. Their `headline statement `_ boasting: "... iPod stores up to 1,000 CD-quality songs on its super-thin 5 GB hard drive, ..." OK. That's pretty simple to work backwards: *capacity of disk drive* divided by *number of songs* equals the average size of a song. Which in this case is: .. code-block:: python :linenos: :emphasize-lines: 3 >>> song_size = GB(5) / 1000 >>> print song_size 0.005GB Or, using ``best_prefix``, (line **2**) to generate a more human-readable form: .. code-block:: python :linenos: :emphasize-lines: 2 >>> song_size = GB(5) / 1000 >>> print song_size.best_prefix() 5.0MB That's great, if you have normal radio-length songs. But how many of our `favorite jam-band's `_ 15-30+ minute-long songs could we fit on this iPod? Let's pretend we did the math and the average audio file worked out to be **18.6 MiB** (19.5 MB) large. .. code-block:: python :linenos: :emphasize-lines: 4 >>> ipod_capacity = GB(5) >>> bootleg_size = MB(19.5) >>> print ipod_capacity / bootleg_size 256.41025641 The result on line **4** tells tells us that we could fit **256** average-quality songs on our iPod. Printing Human-Readable File Sizes in Python ******************************************** In a Python script or interpreter we may wish to print out file sizes in something other than bytes (which is what ``os.path.getsize`` returns). We can use ``bitmath`` to do that too: .. code-block:: python :linenos: :emphasize-lines: 6 >>> import os >>> from bitmath import * >>> these_files = os.listdir('.') >>> for f in these_files: ... f_size = Byte(os.path.getsize(f)) ... print "%s - %s" % (f, f_size.to_KiB()) test_basic_math.py - 3.048828125 KiB __init__.py - 0.1181640625 KiB test_representation.py - 0.744140625 KiB test_to_Type_conversion.py - 2.2119140625 KiB Alternatively, we could simplify things and use :ref:`bitmath.getsize() ` to read the file size directly into a bitmath object: .. code-block:: python :linenos: :emphasize-lines: 5 >>> import os >>> import bitmath >>> these_files = os.listdir('.') >>> for f in these_files: ... print "%s - %s" % (f, bitmath.getsize(f)) test_basic_math.py - 3.048828125 KiB __init__.py - 0.1181640625 KiB test_representation.py - 0.744140625 KiB test_to_Type_conversion.py - 2.2119140625 KiB .. seealso:: :ref:`Instance Formatting ` How to print results in a *prettier* format Calculating Linux BDP and TCP Window Scaling ******************************************** Say we're doing some Linux Kernel TCP performance tuning. For optimum speeds we need to calculate our BDP, or Bandwidth Delay Product. For this we need to calculate certain values to set some kernel tuning parameters to. The point of this tuning is to send the most data we can during a measured round-trip-time without sending more than can be processed. To accomplish this we are resizing our kernel read/write networking/socket buffers. We will see two ways of doing this. The tedious manual way, and the way with bitmath. The Hard Way ============ **Core Networking Values** - ``net.core.rmem_max`` - **Bytes** - Single Value - Default receive buffer size - ``net.core.wmem_max`` - **Bytes** - Single Value - Default write buffer size **System-Wide Memory Limits** - ``net.ipv4.tcp_mem`` - **Pages** - Three Value Vector - The ``max`` field of the parameter is the number of **memory pages** allowed for queueing by all TCP sockets. **Per-Socket Buffers** Per-socket buffer sizes must not exceed the core networking buffer sizes. - ``net.ipv4.tcp_rmem`` - **Bytes** - Three Field Vector - The ``max`` field sets the size of the TCP receive buffer - ``net.ipv4.tcp_wmem`` - **Bytes** - Three Field Vector - As above, but for the write buffer We would normally calculate the optimal BDP and related values following this approach: #. Measure the latency, or round trip time (RTT, measured in milliseconds), between the host we're tuning and our target remote host #. Measure/identify our network transfer rate #. Calculate the BDP (multiply transfer rate by rtt) #. Obtain our current kernel settings #. Adjust settings as necessary But for the sake brevity we'll be working out of an example scenario with a pre-defined RTT and transfer rate. **Scenario** - We have an average network transfer rate of **1Gb/sec** (where ``Gb`` is the SI unit for Gigabits, not Gibibytes: ``GiB``) - Our latency (RTT) is **0.199ms** (milliseconds) **Calculate Manually** Lets calculate the BDP now. Because the kernel parameters expect values in units of bytes and pages we'll have to convert our transfer rate of 1Gb/sec into B/s (Gigabits/second to Bytes/second): - Convert 1Gb into an equivalent **byte** based unit Remember 1 Byte = 8 Bits: .. code-block:: python tx_rate_GB = 1/8 = 0.125 Our equivalent transfer rate is 0.125GB/sec. - Convert our RTT from milliseconds into seconds Remember 1ms = 10\ :sup:`-3`\ s: .. code-block:: python window_seconds = 0.199 * 10^-3 = 0.000199 Our equivalent RTT window is 0.000199s - Next we multiply the transfer rate by the length of our RTT window (in seconds) (The unit analysis for this is ``GB/s * s`` leaving us with ``GB``) .. code-block:: python BDP = rx_rate_GB * window_seconds = 0.125 * 0.000199 = 0.000024875 Our BDP is 0.000024875GB. - Convert 0.000024875GB to bytes: Remember 1GB = 10\ :sup:`9`\ B .. code-block:: python BDP_bytes = 0.000024875 * 10^9 = 24875.0 Our BDP is 24875 bytes (or about 24.3KiB) The :py:mod:`bitmath` way ========================= All of this math can be done much quicker (and with greater accuracy) using the :py:mod:`bitmath` library. Let's see how: .. code-block:: python :linenos: >>> from bitmath import GB >>> tx = 1/8.0 >>> rtt = 0.199 * 10**-3 >>> bdp = (GB(tx * rtt)).to_Byte() >>> print bdp.to_KiB() KiB(24.2919921875) .. note:: To avoid integer rounding during division, don't forget to divide by ``8.0`` rather than ``8`` We could shorten that even further: .. code-block:: python >>> print (GB((1/8.0) * (0.199 * 10**-3))).to_Byte() 24875.0Byte **Get the current kernel parameters** Important to note is that the **per-socket** buffer sizes must not exceed the **core network** buffer sizes. Lets fetch our current core buffer sizes: .. code-block:: console $ sysctl net.core.rmem_max net.core.wmem_max net.core.rmem_max = 212992 net.core.wmem_max = 212992 Recall, these values are in bytes. What are they in KiB? .. code-block:: python >>> print Byte(212992).to_KiB() KiB(208.0) This means our core networking buffer sizes are set to 208KiB each. Now let's check our current per-socket buffer sizes: .. code-block:: console $ sysctl net.ipv4.tcp_rmem net.ipv4.tcp_wmem net.ipv4.tcp_rmem = 4096 87380 6291456 net.ipv4.tcp_wmem = 4096 16384 4194304 Let's double-check that our buffer sizes aren't already out of wack (per-socket should be <= networking core) .. code-block:: python >>> net_core_max = KiB(bytes=212992) >>> ipv4_tcp_rmem_max = KiB(bytes=6291456) >>> ipv4_tcp_rmem_max > net_core_max True It appears that my buffers aren't sized appropriately. We'll fix that when we set the tunable parameters. Finally, how large is the entire system TCP buffer? .. code-block:: console $ sysctl net.ipv4.tcp_mem net.ipv4.tcp_mem = 280632 374176 561264 Our max system TCP buffer size is set to **561264**. Recall that this parameter is measured in **memory pages**. Most of the time your page size is ``4096 bytes``, but you can check by running the command: ``getconf PAGESIZE``. To convert the system TCP buffer size (561264) into a byte-based unit, we'll multiply it by our pagesize (4096): .. code-block:: python >>> sys_pages = 561264 >>> page_size = 4096 >>> sys_buffer = Byte(sys_pages * page_size) >>> print sys_buffer.to_MiB() 2192.4375MiB >>> print sys_buffer.to_GiB() 2.14105224609GiB The system max TCP buffer size is about 2.14GiB. In review, we discovered the following: * Our **core network** buffer size is insufficient (**212992**), we'll set it higher * Our current **per-socket** buffer sizes are **6291456** and **4194304** And we calculated the following: * Our ideal **max** per-socket buffer size is **24875** bytes * Our ideal **default** per-socket buffer size (half the **max**): **12437** **Finally: Set the new kernel parameters** Set the **core-network** buffer sizes: .. code-block:: console $ sudo sysctl net.core.rmem_max=24875 net.core.wmem_max=24875 net.core.rmem_max = 4235 net.core.wmem_max = 4235 Set the **per-socket** buffer sizes: .. code-block:: console $ sudo sysctl net.ipv4.tcp_rmem="4096 12437 24875" net.ipv4.tcp_wmem="4096 12437 24875" net.ipv4.tcp_rmem = 4096 12437 24875 net.ipv4.tcp_wmem = 4096 12437 24875 And it's done! Testing this is left as an exercise for the reader. Note that in my experience this is less useful on wireless connections. .. _real_life_examples_download_progress_bars: Creating Download Progress Bars ******************************* .. literalinclude:: ../../full_demo.py * View the the source for the `demo suite `_ on GitHub .. _real_life_examples_read_device_storage_capacity: Reading a Devices Storage Capacity ********************************** .. include:: query_device_capacity_warning.rst Using :func:`bitmath.query_device_capacity` we can read the size of a storage device or a partition on a device. .. include:: example_block_devices.rst Usage is fairly straight-forward. Create an open file handle of the device you want to read the capacity of and then create a bitmath object with the ``query_device_capacity`` function. Here's an example where we read the capacity of device ``sda``, the first device on the example system. .. code-block:: python >>> import bitmath >>> fh = open('/dev/sda', 'r') >>> sda_capacity = bitmath.query_device_capacity(fh) >>> fh.close() >>> print sda_capacity.best_prefix() 238.474937439 GiB We can simplify this so that the file handle is automatically closed for us by using the ``with`` context manager. .. code-block:: python >>> with open('/dev/sda', 'r') as fh: ... sda_capacity = bitmath.query_device_capacity(fh) >>> print sda_capacity.best_prefix() 238.474937439 GiB bitmath-1.3.3.1/docsite/source/simple_examples.rst000066400000000000000000000205301333755710600221720ustar00rootroot00000000000000Getting Started ############### In this section we will take a high-level look at the basic things you can do with bitmath. We'll include the following topics: .. contents:: :depth: 3 :local: .. _simple_examples_supported_operations: Tables of Supported Operations ****************************** The following legend describes the two operands used in the tables below. ======= ======================================= Operand Description ======= ======================================= ``bm`` A bitmath object is required ``num`` An integer or decimal value is required ======= ======================================= .. _getting_started_arithmetic: Arithmetic ========== Math works mostly like you expect it to, except for a few edge-cases: * Mixing bitmath types with Number types (the result varies per-operation) * Operations where two bitmath types would cancel out (such as dividing two bitmath types) * Multiplying two bitmath instances together is supported, but the results may not make much sense. .. seealso:: :ref:`Appendix: Rules for Math ` For a discussion of the behavior of bitmath and number types. .. _simple_examples_arithmetic_table: +----------------+-------------------+---------------------+---------------------------------------+ | Operation | Parameters | Result Type | Example | +================+===================+=====================+=======================================+ | Addition | ``bm1`` + ``bm2`` | ``type(bm1)`` | ``KiB(1) + MiB(2)`` = ``2049.0KiB`` | +----------------+-------------------+---------------------+---------------------------------------+ | Addition | ``bm`` + ``num`` | ``type(num)`` | ``KiB(1) + 1`` = ``2.0`` | +----------------+-------------------+---------------------+---------------------------------------+ | Addition | ``num`` + ``bm`` | ``type(num)`` | ``1 + KiB(1)`` = ``2.0`` | +----------------+-------------------+---------------------+---------------------------------------+ | Subtraction | ``bm1`` - ``bm2`` | ``type(bm1)`` | ``KiB(1) - Byte(2048)`` = ``-1.0KiB`` | +----------------+-------------------+---------------------+---------------------------------------+ | Subtraction | ``bm`` - ``num`` | ``type(num)`` | ``KiB(4) - 1`` = ``3.0`` | +----------------+-------------------+---------------------+---------------------------------------+ | Subtraction | ``num`` - ``bm`` | ``type(num)`` | ``10 - KiB(1)`` = ``9.0`` | +----------------+-------------------+---------------------+---------------------------------------+ | Multiplication | ``bm1`` * ``bm2`` | ``type(bm1)`` | ``KiB(1) * KiB(2)`` = ``2048.0KiB`` | +----------------+-------------------+---------------------+---------------------------------------+ | Multiplication | ``bm`` * ``num`` | ``type(bm)`` | ``KiB(2) * 3`` = ``6.0KiB`` | +----------------+-------------------+---------------------+---------------------------------------+ | Multiplication | ``num`` * ``bm`` | ``type(bm)`` | ``2 * KiB(3)`` = ``6.0KiB`` | +----------------+-------------------+---------------------+---------------------------------------+ | Division | ``bm1`` / ``bm2`` | ``type(num)`` | ``KiB(1) / KiB(2)`` = ``0.5`` | +----------------+-------------------+---------------------+---------------------------------------+ | Division | ``bm`` / ``num`` | ``type(bm)`` | ``KiB(1) / 3`` = ``0.3330078125KiB`` | +----------------+-------------------+---------------------+---------------------------------------+ | Division | ``num`` / ``bm`` | ``type(num)`` | ``3 / KiB(2)`` = ``1.5`` | +----------------+-------------------+---------------------+---------------------------------------+ Bitwise Operations ================== .. seealso:: `Bitwise Calculator `_ A free online calculator for checking your math Bitwise operations are also supported. Bitwise operations work directly on the ``bits`` attribute of a bitmath instance, not the number you see in an instances printed representation (``value``), to maintain accuracy. +----------------+-----------------------+--------------+---------------------------------------------------------+ | Operation | Parameters | Result Type | Example\ :sup:`1` | +================+=======================+==============+=========================================================+ | Left Shift | ``bm`` << ``num`` | ``type(bm)`` | ``MiB(1)`` << ``2`` = ``MiB(4.0)`` | +----------------+-----------------------+--------------+---------------------------------------------------------+ | Right Shift | ``bm`` >> ``num`` | ``type(bm)`` | ``MiB(1)`` >> ``2`` = ``MiB(0.25)`` | +----------------+-----------------------+--------------+---------------------------------------------------------+ | AND | ``bm`` & ``num`` | ``type(bm)`` | ``MiB(13.37)`` & ``1337`` = ``MiB(0.000126...)`` | +----------------+-----------------------+--------------+---------------------------------------------------------+ | OR | ``bm`` \| ``num`` | ``type(bm)`` | ``MiB(13.37)`` \| ``1337`` = ``MiB(13.3700...)`` | +----------------+-----------------------+--------------+---------------------------------------------------------+ | XOR | ``bm`` ^ ``num`` | ``type(bm)`` | ``MiB(13.37)`` ^ ``1337`` = ``MiB(13.369...)`` | +----------------+-----------------------+--------------+---------------------------------------------------------+ 1. *Give me a break here, it's not easy coming up with compelling examples for bitwise operations...* Basic Math ********** bitmath supports all arithmetic operations .. code-block:: python :linenos: >>> eighty_four_mib = fourty_two_mib + fourty_two_mib_in_kib >>> eighty_four_mib MiB(84.0) >>> eighty_four_mib == fourty_two_mib * 2 True Unit Conversion *************** .. code-block:: python :linenos: >>> from bitmath import * >>> fourty_two_mib = MiB(42) >>> fourty_two_mib_in_kib = fourty_two_mib.to_KiB() >>> fourty_two_mib_in_kib KiB(43008.0) >>> fourty_two_mib MiB(42.0) >>> fourty_two_mib.KiB KiB(43008.0) Rich Comparison *************** Rich Comparison (as per the `Python Basic Customization `_ magic methods) ``<``, ``<=``, ``==``, ``!=``, ``>``, ``>=`` is fully supported: .. code-block:: python :linenos: >>> GB(1) < GiB(1) True >>> GB(1.073741824) == GiB(1) True >>> GB(1.073741824) <= GiB(1) True >>> Bit(1) == TiB(bits=1) True >>> kB(100) > EiB(bytes=1024) True >>> kB(100) >= EiB.from_other(kB(100)) True >>> kB(100) >= EiB.from_other(kB(99)) True >>> kB(100) >= EiB.from_other(kB(9999)) False >>> KiB(100) != Byte(1) True Sorting ******* bitmath natively supports sorting. Let's make a list of the size (in bytes) of all the files in the present working directory (lines **4** and **5**) and then print them out sorted by increasing magnitude (lines **10** and **11**, and **13** → **15**): .. code-block:: python :linenos: :emphasize-lines: 4,5,10,11,13,14,15 >>> from bitmath import * >>> import os >>> sizes = [] >>> for f in os.listdir('./tests/'): ... sizes.append(KiB(os.path.getsize('./tests/' + f))) >>> print sizes [KiB(7337.0), KiB(1441.0), KiB(2126.0), KiB(2178.0), KiB(2326.0), KiB(4003.0), KiB(48.0), KiB(1770.0), KiB(7892.0), KiB(4190.0)] >>> print sorted(sizes) [KiB(48.0), KiB(1441.0), KiB(1770.0), KiB(2126.0), KiB(2178.0), KiB(2326.0), KiB(4003.0), KiB(4190.0), KiB(7337.0), KiB(7892.0)] >>> human_sizes = [s.best_prefix() for s in sizes] >>> print sorted(human_sizes) [KiB(48.0), MiB(1.4072265625), MiB(1.728515625), MiB(2.076171875), MiB(2.126953125), MiB(2.271484375), MiB(3.9091796875), MiB(4.091796875), MiB(7.1650390625), MiB(7.70703125)] Now print them out in descending magnitude .. code-block:: python >>> print sorted(human_sizes, reverse=True) [KiB(7892.0), KiB(7337.0), KiB(4190.0), KiB(4003.0), KiB(2326.0), KiB(2178.0), KiB(2126.0), KiB(1770.0), KiB(1441.0), KiB(48.0)] bitmath-1.3.3.1/full_demo.py000077500000000000000000000146651333755710600156560ustar00rootroot00000000000000#!/usr/bin/env python from __future__ import print_function import logging import time import bitmath import bitmath.integrations import argparse import requests import progressbar import os import tempfile import atexit import random from functools import reduce # Files of various sizes to use in the demo. # # Moar here: https://www.kernel.org/pub/linux/kernel/v3.0/?C=S;O=D REMOTES = [ # patch-3.0.70.gz 20-Mar-2013 20:02 1.0M 'https://www.kernel.org/pub/linux/kernel/v3.0/patch-3.4.92.xz', # patch-3.16.gz 03-Aug-2014 22:39 8.0M 'https://www.kernel.org/pub/linux/kernel/v3.0/patch-3.16.gz', # patch-3.2.gz 05-Jan-2012 00:43 22M 'https://www.kernel.org/pub/linux/kernel/v3.0/patch-3.2.gz', ] ###################################################################### p = argparse.ArgumentParser(description='bitmath demo suite') p.add_argument('-d', '--down', help="Download Rate", type=bitmath.integrations.BitmathType, default=bitmath.MiB(4)) p.add_argument('-s', '--slowdown', help='Randomly pause to slow down the transfer rate', action='store_true', default=False) args = p.parse_args() ###################################################################### # Save our example files somewhere. And then clean up every trace that # anything every happened there. shhhhhhhhhhhhhhhh DESTDIR = tempfile.mkdtemp('demosuite', 'bitmath') @atexit.register def cleanup(): for f in os.listdir(DESTDIR): os.remove(os.path.join(DESTDIR, f)) os.rmdir(DESTDIR) ###################################################################### for f in REMOTES: print(""" ######################################################################""") fname = os.path.basename(f) # An array of widgets to design our progress bar. Note how we use # BitmathFileTransferSpeed widgets = ['Bitmath Demo Suite (%s): ' % fname, progressbar.Percentage(), ' ', progressbar.Bar(marker=progressbar.RotatingMarker()), ' ', progressbar.ETA(), ' ', bitmath.integrations.BitmathFileTransferSpeed()] # The 'stream' keyword lets us http GET files in # chunks. http://docs.python-requests.org/en/latest/user/quickstart/#raw-response-content r = requests.get(f, stream=True) # We haven't began receiving the payload content yet, we have only # just received the response headers. Of interest is the # 'content-length' header which describes our payload in bytes # # http://bitmath.readthedocs.org/en/latest/classes.html#bitmath.Byte size = bitmath.Byte(int(r.headers['Content-Length'])) # Demonstrate 'with' context handler, allowing us to customize all # bitmath string printing within the indented block. We don't need # all that precision anyway, just two points should do. # # http://bitmath.readthedocs.org/en/latest/module.html#bitmath-format with bitmath.format("{value:.2f} {unit}"): print("Downloading %s (%s) in %s chunks" % (f, size.best_prefix(), args.down.best_prefix())) # We have to save these files somewhere save_path = os.path.join(DESTDIR, fname) print("Saving to: %s" % save_path) print("") # OK. Let's create our actual progress bar now. See the 'maxval' # keyword? That's the size of our payload in bytes. pbar = progressbar.ProgressBar( widgets=widgets, maxval=int(size)).start() ###################################################################### # Open a new file for binary writing and write 'args.down' size # chunks into it until we've received the entire payload with open(save_path, 'wb') as fd: # The 'iter_content' method accepts integer values of # bytes. Lucky for us, 'args.down' is a bitmath instance and # has a 'bytes' attribute we can feed into the method call. for chunk in r.iter_content(int(args.down.bytes)): fd.write(chunk) # The progressbar will end the entire cosmos as we know it # if we try to .update() it beyond it's MAXVAL # parameter. # # That's something I'd like to avoid taking the # responsibility for. if (pbar.currval + args.down.bytes) < pbar.maxval: pbar.update(pbar.currval + int(args.down.bytes)) # We can add an pause to artificially speed up/slowdown # the transfer rate. Allows us to see different units. if args.slowdown: # randomly slow down 1/5 of the time if random.randrange(0, 100) % 5 == 0: time.sleep(random.randrange(0, 500) * 0.01) # Nothing to see here. Go home. pbar.finish() ###################################################################### print(""" ###################################################################### List downloaded contents * Filter for .xz files only """) for p,bm in bitmath.listdir(DESTDIR, filter='*.xz'): print(p, bm) ###################################################################### print(""" ###################################################################### List downloaded contents * Filter for .gz files only * Print using best human readable prefix """) for p,bm in bitmath.listdir(DESTDIR, filter='*.gz', bestprefix=True): print(p, bm) ###################################################################### print(""" ###################################################################### List downloaded contents * No filter set, to display all files * Limit precision of printed file size to 3 digits * Print using best human readable prefix """) for p,bm in bitmath.listdir(DESTDIR, bestprefix=True): with bitmath.format("{value:.3f} {unit}"): print(p, bm) ###################################################################### print(""" ###################################################################### Sum the size of all downloaded files together * Print with best prefix and 3 digits of precision """) discovered_files = [f[1] for f in bitmath.listdir(DESTDIR)] total_size = reduce(lambda x,y: x+y, discovered_files).best_prefix().format("{value:.3f} {unit}") print("Total size of %s downloaded items: %s" % (len(discovered_files), total_size)) bitmath-1.3.3.1/python-bitmath.spec000066400000000000000000000251671333755710600171550ustar00rootroot00000000000000%if 0%{?rhel} && 0%{?rhel} <= 6 %{!?__python2: %global __python2 /usr/bin/python2} %{!?python2_sitelib: %global python2_sitelib %(%{__python2} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())")} %{!?python2_sitearch: %global python2_sitearch %(%{__python2} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(1))")} %{!?py2_build: %global py2_build python setup.py build} %{!?py2_install: %global py2_install python setup.py install -O1 --root=$RPM_BUILD_ROOT} %endif %if 0%{?fedora} %{!?python3_version: %global python3_version %(%{__python3} -c "import sys; sys.stdout.write(sys.version[:3])")} %global with_python3 1 %else %global with_python3 0 %endif %global _short_name bitmath %global _short_release 1 Name: python-bitmath Summary: Aids representing and manipulating file sizes in various prefix notations Version: 1.3.3 Release: %{_short_release}%{?dist} Group: Development/Libraries License: BSD Source0: https://github.com/tbielawa/bitmath/archive/%{version}.%{_short_release}.tar.gz Url: https://github.com/tbielawa/bitmath BuildArch: noarch BuildRequires: python2-mock BuildRequires: python2-nose BuildRequires: python2-progressbar BuildRequires: python2-setuptools BuildRequires: python2-devel %if 0%{?with_python3} BuildRequires: python3-devel BuildRequires: python3-mock BuildRequires: python3-nose BuildRequires: python3-setuptools %endif %{?el6:Requires: python-argparse} %{?el6:BuildRequires: python-argparse} %{?el6:BuildRequires: python-unittest2} %description bitmath simplifies many facets of interacting with file sizes in various units. Examples include: converting between SI and NIST prefix units (GiB to kB), converting between units of the same type (SI to SI, or NIST to NIST), basic arithmetic operations (subtracting 42KiB from 50GiB), and rich comparison operations (1024 Bytes == 1KiB), bitwise operations, sorting, automatic best human-readable prefix selection, and completely customizable formatting. In addition to the conversion and math operations, bitmath provides human readable representations of values which are suitable for use in interactive shells as well as larger scripts and applications. It can also read the capacity of system storage devices. bitmath can parse strings (like "1 KiB") into proper objects and has support for integration with the argparse module as a custom argument type and the progressbar module as a custom file transfer speed widget. bitmath is thoroughly unittested, with almost 200 individual tests (a number which is always increasing). bitmath's test-coverage is almost always at 100%. ###################################################################### # Sub-package setup %package -n python2-bitmath Summary: Aids representing and manipulating file sizes in various prefix notations %{?python_provide:%python_provide python2-bitmath} %description -n python2-bitmath bitmath simplifies many facets of interacting with file sizes in various units. Examples include: converting between SI and NIST prefix units (GiB to kB), converting between units of the same type (SI to SI, or NIST to NIST), basic arithmetic operations (subtracting 42KiB from 50GiB), and rich comparison operations (1024 Bytes == 1KiB), bitwise operations, sorting, automatic best human-readable prefix selection, and completely customizable formatting. In addition to the conversion and math operations, bitmath provides human readable representations of values which are suitable for use in interactive shells as well as larger scripts and applications. It can also read the capacity of system storage devices. bitmath can parse strings (like "1 KiB") into proper objects and has support for integration with the argparse module as a custom argument type and the progressbar module as a custom file transfer speed widget. bitmath is thoroughly unittested, with almost 200 individual tests (a number which is always increasing). bitmath's test-coverage is almost always at 100%. #--------------------------------------------------------------------- %if 0%{?with_python3} %package -n python3-bitmath Summary: Aids representing and manipulating file sizes in various prefix notations %{?python_provide:%python_provide python3-bitmath} %description -n python3-bitmath bitmath simplifies many facets of interacting with file sizes in various units. Examples include: converting between SI and NIST prefix units (GiB to kB), converting between units of the same type (SI to SI, or NIST to NIST), basic arithmetic operations (subtracting 42KiB from 50GiB), and rich comparison operations (1024 Bytes == 1KiB), bitwise operations, sorting, automatic best human-readable prefix selection, and completely customizable formatting. In addition to the conversion and math operations, bitmath provides human readable representations of values which are suitable for use in interactive shells as well as larger scripts and applications. It can also read the capacity of system storage devices. bitmath can parse strings (like "1 KiB") into proper objects and has support for integration with the argparse module as a custom argument type and the progressbar module as a custom file transfer speed widget. bitmath is thoroughly unittested, with almost 200 individual tests (a number which is always increasing). bitmath's test-coverage is almost always at 100%. %endif # with_python3 ###################################################################### %check nosetests -v %if 0%{?with_python3} # We can't run the progressbar and argparse tests in python3 until # progressbar has a python3 package available :( # # Skip those tests for now and run the rest nosetests-%{python3_version} -e 'test_FileTransferSpeed' \ -e 'test_BitmathType_' \ -I '.*test_argparse_type.py' \ -I '.*test_progressbar.py' -v %endif # with_python3 ###################################################################### %prep %setup -n bitmath-%{version}.%{_short_release} -q ###################################################################### %build %py2_build %if 0%{?with_python3} %py3_build %endif ###################################################################### %install %py2_install mv $RPM_BUILD_ROOT/%{_bindir}/bitmath $RPM_BUILD_ROOT/%{_bindir}/bitmath-2.7 %if 0%{?with_python3} %py3_install pushd $RPM_BUILD_ROOT/%{_bindir}/ ln -s bitmath bitmath-%{python3_version} popd %endif # with_python3 mkdir -p $RPM_BUILD_ROOT/%{_mandir}/man1/ cp -v *.1 $RPM_BUILD_ROOT/%{_mandir}/man1/ mkdir -p $RPM_BUILD_ROOT/%{_docdir}/%{name}/docs cp -v -r docsite/source/* $RPM_BUILD_ROOT/%{_docdir}/%{name}/docs/ rm -f $RPM_BUILD_ROOT/%{_docdir}/%{name}/docs/NEWS.rst ###################################################################### %files -n python2-bitmath %{python2_sitelib}/* %doc README.rst NEWS.rst LICENSE %doc %{_mandir}/man1/bitmath.1* %doc %{_docdir}/%{name}/docs/ %{_bindir}/bitmath-2.7 %if 0%{?with_python3} %files -n python3-bitmath %{python3_sitelib}/* %doc README.rst NEWS.rst LICENSE %doc %{_mandir}/man1/bitmath.1* %doc %{_docdir}/%{name}/docs/ %{_bindir}/bitmath %{_bindir}/bitmath-%{python3_version} %endif # with_python3 ###################################################################### %changelog * Thu Aug 23 2018 Tim Bielawa - 1.3.3-1 - New release * Sat Mar 17 2018 Tim Bielawa - 1.3.2-1 - New release * Sun Jul 17 2016 Tim Bielawa - 1.3.1-1 - New release * Tue Jan 12 2016 Tim Bielawa - 1.3.0-2 - Packaging update * Fri Jan 8 2016 Tim Bielawa - 1.3.0-1 - Fix best_prefix for negative values GitHub: #55 * Tue Dec 29 2015 Tim Bielawa - 1.2.4-3 - Fix tests to run on koji - Minor packaging changes * Mon Nov 30 2015 Tim Bielawa - 1.2.4-1 - New release. Now builds dual python2.x and 3.x packages. - New function: query_device_capacity - Minor bug fixes for everyone! * Sun Jan 4 2015 Tim Bielawa - 1.2.3-3 - Add mock to build requires * Sun Jan 4 2015 Tim Bielawa - 1.2.3-2 - Add python-progressbar build-dependency to satisfy 'check' tests * Sun Jan 4 2015 Tim Bielawa - 1.2.3-1 - Add progressbar example to the README * Sun Jan 4 2015 Tim Bielawa - 1.2.2-1 - Fix some problems with the automated build system * Sun Jan 4 2015 Tim Bielawa - 1.2.1-1 - Add a new integration: the progressbar module FileTransferSpeed widget * Mon Dec 29 2014 Tim Bielawa - 1.2.0-1 - Add argparse integration with a BitmathType argument type * Sat Dec 20 2014 Tim Bielawa - 1.1.0-1 - New parse_string utility function from tonycpsu - 'bitmath' tool added for converting on the command line * Fri Aug 15 2014 Tim Bielawa - 1.0.8-3 - Actually fix this whole specfile and version mixup * Fri Aug 15 2014 Tim Bielawa - 1.0.8-2 - Fix macro expansion in specfile changelog * Thu Aug 14 2014 Tim Bielawa - 1.0.8-1 - First release with contributors: davidfischer-ch and hikusukih! Thank you! - Real documentation (via readthedocs.org) - Significant formatting functionality added: - +formatting context manager, listdir, getsize - Python3 compat via rtruediv contribution! - So many more unit tests - Coveralls code-coverage review - Pluralization/singularity in string formatting (thanks for the contribution!) * Sat Jul 19 2014 Tim Bielawa - 1.0.7-1 - Lots of documentation and unittest updates - See GitHub Milestone 2: 1.0.7 for a list of closed issues * Mon Jul 14 2014 Tim Bielawa - 1.0.6-1 - New instance properties - Custom representation formatting method. #9 - Best-prefix guessing: select the best human-readable prefix unit automatically. #6 - Bitwise operation support. #3 - More unittests than your body has room for * Mon Apr 28 2014 Tim Bielawa - 1.0.5-1 - Now with support for bitwise operations * Thu Mar 20 2014 Tim Bielawa - 1.0.4-1 - Plenty of documentation updates - Fix some issues with mix-type math operations. - More unit tests! * Mon Mar 17 2014 Tim Bielawa - 1.0.3-1 - Big issue converting NIST to SI - Also, retroactively remove unexpanded macros from changelog * Thu Mar 13 2014 Tim Bielawa - 1.0.2-3 - Bump release for new archive format * Thu Mar 13 2014 Tim Bielawa - 1.0.2-2 - Bump spec for proper Source0 versioning * Thu Mar 13 2014 Tim Bielawa - 1.0.2-1 - First real solid release with full functionality and documentation * Tue Mar 11 2014 Tim Bielawa - 1.0.0-1 - First release bitmath-1.3.3.1/python-bitmath.spec.in000066400000000000000000000251731333755710600175570ustar00rootroot00000000000000%if 0%{?rhel} && 0%{?rhel} <= 6 %{!?__python2: %global __python2 /usr/bin/python2} %{!?python2_sitelib: %global python2_sitelib %(%{__python2} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())")} %{!?python2_sitearch: %global python2_sitearch %(%{__python2} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(1))")} %{!?py2_build: %global py2_build python setup.py build} %{!?py2_install: %global py2_install python setup.py install -O1 --root=$RPM_BUILD_ROOT} %endif %if 0%{?fedora} %{!?python3_version: %global python3_version %(%{__python3} -c "import sys; sys.stdout.write(sys.version[:3])")} %global with_python3 1 %else %global with_python3 0 %endif %global _short_name bitmath %global _short_release 1 Name: python-bitmath Summary: Aids representing and manipulating file sizes in various prefix notations Version: %VERSION% Release: %{_short_release}%{?dist} Group: Development/Libraries License: BSD Source0: https://github.com/tbielawa/bitmath/archive/%{version}.%{_short_release}.tar.gz Url: https://github.com/tbielawa/bitmath BuildArch: noarch BuildRequires: python2-mock BuildRequires: python2-nose BuildRequires: python2-progressbar BuildRequires: python2-setuptools BuildRequires: python2-devel %if 0%{?with_python3} BuildRequires: python3-devel BuildRequires: python3-mock BuildRequires: python3-nose BuildRequires: python3-setuptools %endif %{?el6:Requires: python-argparse} %{?el6:BuildRequires: python-argparse} %{?el6:BuildRequires: python-unittest2} %description bitmath simplifies many facets of interacting with file sizes in various units. Examples include: converting between SI and NIST prefix units (GiB to kB), converting between units of the same type (SI to SI, or NIST to NIST), basic arithmetic operations (subtracting 42KiB from 50GiB), and rich comparison operations (1024 Bytes == 1KiB), bitwise operations, sorting, automatic best human-readable prefix selection, and completely customizable formatting. In addition to the conversion and math operations, bitmath provides human readable representations of values which are suitable for use in interactive shells as well as larger scripts and applications. It can also read the capacity of system storage devices. bitmath can parse strings (like "1 KiB") into proper objects and has support for integration with the argparse module as a custom argument type and the progressbar module as a custom file transfer speed widget. bitmath is thoroughly unittested, with almost 200 individual tests (a number which is always increasing). bitmath's test-coverage is almost always at 100%. ###################################################################### # Sub-package setup %package -n python2-bitmath Summary: Aids representing and manipulating file sizes in various prefix notations %{?python_provide:%python_provide python2-bitmath} %description -n python2-bitmath bitmath simplifies many facets of interacting with file sizes in various units. Examples include: converting between SI and NIST prefix units (GiB to kB), converting between units of the same type (SI to SI, or NIST to NIST), basic arithmetic operations (subtracting 42KiB from 50GiB), and rich comparison operations (1024 Bytes == 1KiB), bitwise operations, sorting, automatic best human-readable prefix selection, and completely customizable formatting. In addition to the conversion and math operations, bitmath provides human readable representations of values which are suitable for use in interactive shells as well as larger scripts and applications. It can also read the capacity of system storage devices. bitmath can parse strings (like "1 KiB") into proper objects and has support for integration with the argparse module as a custom argument type and the progressbar module as a custom file transfer speed widget. bitmath is thoroughly unittested, with almost 200 individual tests (a number which is always increasing). bitmath's test-coverage is almost always at 100%. #--------------------------------------------------------------------- %if 0%{?with_python3} %package -n python3-bitmath Summary: Aids representing and manipulating file sizes in various prefix notations %{?python_provide:%python_provide python3-bitmath} %description -n python3-bitmath bitmath simplifies many facets of interacting with file sizes in various units. Examples include: converting between SI and NIST prefix units (GiB to kB), converting between units of the same type (SI to SI, or NIST to NIST), basic arithmetic operations (subtracting 42KiB from 50GiB), and rich comparison operations (1024 Bytes == 1KiB), bitwise operations, sorting, automatic best human-readable prefix selection, and completely customizable formatting. In addition to the conversion and math operations, bitmath provides human readable representations of values which are suitable for use in interactive shells as well as larger scripts and applications. It can also read the capacity of system storage devices. bitmath can parse strings (like "1 KiB") into proper objects and has support for integration with the argparse module as a custom argument type and the progressbar module as a custom file transfer speed widget. bitmath is thoroughly unittested, with almost 200 individual tests (a number which is always increasing). bitmath's test-coverage is almost always at 100%. %endif # with_python3 ###################################################################### %check nosetests -v %if 0%{?with_python3} # We can't run the progressbar and argparse tests in python3 until # progressbar has a python3 package available :( # # Skip those tests for now and run the rest nosetests-%{python3_version} -e 'test_FileTransferSpeed' \ -e 'test_BitmathType_' \ -I '.*test_argparse_type.py' \ -I '.*test_progressbar.py' -v %endif # with_python3 ###################################################################### %prep %setup -n bitmath-%{version}.%{_short_release} -q ###################################################################### %build %py2_build %if 0%{?with_python3} %py3_build %endif ###################################################################### %install %py2_install mv $RPM_BUILD_ROOT/%{_bindir}/bitmath $RPM_BUILD_ROOT/%{_bindir}/bitmath-2.7 %if 0%{?with_python3} %py3_install pushd $RPM_BUILD_ROOT/%{_bindir}/ ln -s bitmath bitmath-%{python3_version} popd %endif # with_python3 mkdir -p $RPM_BUILD_ROOT/%{_mandir}/man1/ cp -v *.1 $RPM_BUILD_ROOT/%{_mandir}/man1/ mkdir -p $RPM_BUILD_ROOT/%{_docdir}/%{name}/docs cp -v -r docsite/source/* $RPM_BUILD_ROOT/%{_docdir}/%{name}/docs/ rm -f $RPM_BUILD_ROOT/%{_docdir}/%{name}/docs/NEWS.rst ###################################################################### %files -n python2-bitmath %{python2_sitelib}/* %doc README.rst NEWS.rst LICENSE %doc %{_mandir}/man1/bitmath.1* %doc %{_docdir}/%{name}/docs/ %{_bindir}/bitmath-2.7 %if 0%{?with_python3} %files -n python3-bitmath %{python3_sitelib}/* %doc README.rst NEWS.rst LICENSE %doc %{_mandir}/man1/bitmath.1* %doc %{_docdir}/%{name}/docs/ %{_bindir}/bitmath %{_bindir}/bitmath-%{python3_version} %endif # with_python3 ###################################################################### %changelog * Thu Aug 23 2018 Tim Bielawa - 1.3.3-1 - New release * Sat Mar 17 2018 Tim Bielawa - 1.3.2-1 - New release * Sun Jul 17 2016 Tim Bielawa - 1.3.1-1 - New release * Tue Jan 12 2016 Tim Bielawa - 1.3.0-2 - Packaging update * Fri Jan 8 2016 Tim Bielawa - 1.3.0-1 - Fix best_prefix for negative values GitHub: #55 * Tue Dec 29 2015 Tim Bielawa - 1.2.4-3 - Fix tests to run on koji - Minor packaging changes * Mon Nov 30 2015 Tim Bielawa - 1.2.4-1 - New release. Now builds dual python2.x and 3.x packages. - New function: query_device_capacity - Minor bug fixes for everyone! * Sun Jan 4 2015 Tim Bielawa - 1.2.3-3 - Add mock to build requires * Sun Jan 4 2015 Tim Bielawa - 1.2.3-2 - Add python-progressbar build-dependency to satisfy 'check' tests * Sun Jan 4 2015 Tim Bielawa - 1.2.3-1 - Add progressbar example to the README * Sun Jan 4 2015 Tim Bielawa - 1.2.2-1 - Fix some problems with the automated build system * Sun Jan 4 2015 Tim Bielawa - 1.2.1-1 - Add a new integration: the progressbar module FileTransferSpeed widget * Mon Dec 29 2014 Tim Bielawa - 1.2.0-1 - Add argparse integration with a BitmathType argument type * Sat Dec 20 2014 Tim Bielawa - 1.1.0-1 - New parse_string utility function from tonycpsu - 'bitmath' tool added for converting on the command line * Fri Aug 15 2014 Tim Bielawa - 1.0.8-3 - Actually fix this whole specfile and version mixup * Fri Aug 15 2014 Tim Bielawa - 1.0.8-2 - Fix macro expansion in specfile changelog * Thu Aug 14 2014 Tim Bielawa - 1.0.8-1 - First release with contributors: davidfischer-ch and hikusukih! Thank you! - Real documentation (via readthedocs.org) - Significant formatting functionality added: - +formatting context manager, listdir, getsize - Python3 compat via rtruediv contribution! - So many more unit tests - Coveralls code-coverage review - Pluralization/singularity in string formatting (thanks for the contribution!) * Sat Jul 19 2014 Tim Bielawa - 1.0.7-1 - Lots of documentation and unittest updates - See GitHub Milestone 2: 1.0.7 for a list of closed issues * Mon Jul 14 2014 Tim Bielawa - 1.0.6-1 - New instance properties - Custom representation formatting method. #9 - Best-prefix guessing: select the best human-readable prefix unit automatically. #6 - Bitwise operation support. #3 - More unittests than your body has room for * Mon Apr 28 2014 Tim Bielawa - 1.0.5-1 - Now with support for bitwise operations * Thu Mar 20 2014 Tim Bielawa - 1.0.4-1 - Plenty of documentation updates - Fix some issues with mix-type math operations. - More unit tests! * Mon Mar 17 2014 Tim Bielawa - 1.0.3-1 - Big issue converting NIST to SI - Also, retroactively remove unexpanded macros from changelog * Thu Mar 13 2014 Tim Bielawa - 1.0.2-3 - Bump release for new archive format * Thu Mar 13 2014 Tim Bielawa - 1.0.2-2 - Bump spec for proper Source0 versioning * Thu Mar 13 2014 Tim Bielawa - 1.0.2-1 - First real solid release with full functionality and documentation * Tue Mar 11 2014 Tim Bielawa - 1.0.0-1 - First release bitmath-1.3.3.1/requirements-py3.txt000066400000000000000000000001231333755710600173100ustar00rootroot00000000000000python-coveralls coverage mock nose nose-cover3 pyflakes pycodestyle progressbar33 bitmath-1.3.3.1/requirements.txt000066400000000000000000000001101333755710600165730ustar00rootroot00000000000000python-coveralls coverage mock nose pyflakes pycodestyle progressbar231 bitmath-1.3.3.1/setup.py000066400000000000000000000065721333755710600150430ustar00rootroot00000000000000# -*- coding: utf-8 -*- # The MIT License (MIT) # # Copyright © 2014 Tim Bielawa # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. from __future__ import print_function try: from setuptools import setup except ImportError: print("Command line script will not be created.") from distutils.core import setup pypi_notice = open('README.rst', 'r').read() setup( name='bitmath', version='1.3.3.1', description='Pythonic module for representing and manipulating file sizes with different prefix notations (file size unit conversion)', long_description=pypi_notice, maintainer='Tim Bielawa', maintainer_email='timbielawa@gmail.com', url='https://github.com/tbielawa/bitmath', license='MIT', package_dir={'bitmath': 'bitmath'}, packages=['bitmath'], classifiers = [ 'Development Status :: 5 - Production/Stable', 'Environment :: Console', 'Intended Audience :: Developers', 'Intended Audience :: Information Technology', 'Intended Audience :: System Administrators', 'Intended Audience :: Telecommunications Industry', 'License :: OSI Approved :: MIT License', 'Operating System :: MacOS :: MacOS X', 'Operating System :: POSIX :: Linux', 'Operating System :: POSIX', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.1', 'Programming Language :: Python :: 3.2', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python', 'Topic :: Scientific/Engineering :: Mathematics', 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Software Development :: Libraries', 'Topic :: Software Development :: User Interfaces', 'Topic :: Software Development :: Widget Sets', 'Topic :: System :: Filesystems', 'Topic :: Text Processing :: Filters', 'Topic :: Utilities' ], entry_points = { 'console_scripts': [ 'bitmath = bitmath:cli_script', ], } ) bitmath-1.3.3.1/setup.py.in000066400000000000000000000063021333755710600154370ustar00rootroot00000000000000# -*- coding: utf-8 -*- # The MIT License (MIT) # # Copyright © 2014 Tim Bielawa # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. from __future__ import print_function try: from setuptools import setup except ImportError: print("Command line script will not be created.") from distutils.core import setup pypi_notice = open('README.rst', 'r').read() setup( name='bitmath', version='%VERSION%.%RELEASE%', description='Pythonic module for representing and manipulating file sizes with different prefix notations (file size unit conversion)', long_description=pypi_notice, maintainer='Tim Bielawa', maintainer_email='timbielawa@gmail.com', url='https://github.com/tbielawa/bitmath', license='MIT', package_dir={'bitmath': 'bitmath'}, packages=['bitmath'], classifiers = [ 'Development Status :: 5 - Production/Stable', 'Environment :: Console', 'Intended Audience :: Developers', 'Intended Audience :: Information Technology', 'Intended Audience :: System Administrators', 'Intended Audience :: Telecommunications Industry', 'License :: OSI Approved :: MIT License', 'Operating System :: MacOS :: MacOS X', 'Operating System :: POSIX :: Linux', 'Operating System :: POSIX', 'Programming Language :: Python :: 2', 'Programming Language :: Python :: 2.6', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.1', 'Programming Language :: Python :: 3.2', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python', 'Topic :: Scientific/Engineering :: Mathematics', 'Topic :: Software Development :: Libraries :: Python Modules', 'Topic :: Software Development :: Libraries', 'Topic :: Software Development :: User Interfaces', 'Topic :: Software Development :: Widget Sets', 'Topic :: System :: Filesystems', 'Topic :: Text Processing :: Filters', 'Topic :: Utilities' ], entry_points = { 'console_scripts': [ 'bitmath = bitmath:cli_script', ], } ) bitmath-1.3.3.1/tests/000077500000000000000000000000001333755710600144615ustar00rootroot00000000000000bitmath-1.3.3.1/tests/__init__.py000066400000000000000000000037461333755710600166040ustar00rootroot00000000000000# -*- coding: utf-8 -*- # The MIT License (MIT) # # Copyright © 2014 Tim Bielawa # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. import platform (major, minor, patch) = platform.python_version_tuple() if int(major) == 2 and int(minor) < 7: import unittest2 as unittest else: import unittest class TestCase(unittest.TestCase): """ Parent TestCase to use for all tests. """ def assertListEqual(self, l1, l2, msg=None): """Assert that the contents of l1 and l2 are equal (disregarding ordering)""" self.assertEqual(len(l1), len(l2)) # OK, the lists are of the same size. Let's test that each # item in l1 is in l2. This assumes that what you provided in # l1 are what you expected to find in l2. for item in l1: if item not in l2: raise AssertionError("List 1 and list 2 are not equivalent: %s %s" % ( str(l1), str(l2))) return True bitmath-1.3.3.1/tests/file_sizes/000077500000000000000000000000001333755710600166155ustar00rootroot00000000000000bitmath-1.3.3.1/tests/file_sizes/bytes.test000066400000000000000000000000461333755710600206440ustar00rootroot00000000000000This file is only a few bytes in size.bitmath-1.3.3.1/tests/file_sizes/kbytes.test000066400000000000000000000020001333755710600210070ustar00rootroot00000000000000aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaabitmath-1.3.3.1/tests/listdir/000077500000000000000000000000001333755710600161335ustar00rootroot00000000000000bitmath-1.3.3.1/tests/listdir/10_byte_file000066400000000000000000000000121333755710600203110ustar00rootroot000000000000001234567890bitmath-1.3.3.1/tests/listdir_nosymlinks/000077500000000000000000000000001333755710600204215ustar00rootroot00000000000000bitmath-1.3.3.1/tests/listdir_nosymlinks/depth1/000077500000000000000000000000001333755710600216065ustar00rootroot00000000000000bitmath-1.3.3.1/tests/listdir_nosymlinks/depth1/depth2/000077500000000000000000000000001333755710600227745ustar00rootroot00000000000000bitmath-1.3.3.1/tests/listdir_nosymlinks/depth1/depth2/1024_byte_file000066400000000000000000000020001333755710600253170ustar00rootroot000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bitmath-1.3.3.1/tests/listdir_nosymlinks/depth1/depth2/10_byte_file000066400000000000000000000000121333755710600251520ustar00rootroot000000000000001234567890bitmath-1.3.3.1/tests/listdir_symlinks/000077500000000000000000000000001333755710600200645ustar00rootroot00000000000000bitmath-1.3.3.1/tests/listdir_symlinks/10_byte_file_link000077700000000000000000000000001333755710600273332../listdir/10_byte_fileustar00rootroot00000000000000bitmath-1.3.3.1/tests/listdir_symlinks/depth1/000077500000000000000000000000001333755710600212515ustar00rootroot00000000000000bitmath-1.3.3.1/tests/listdir_symlinks/depth1/depth2/000077500000000000000000000000001333755710600224375ustar00rootroot00000000000000bitmath-1.3.3.1/tests/listdir_symlinks/depth1/depth2/10_byte_file000066400000000000000000000000121333755710600246150ustar00rootroot000000000000001234567890bitmath-1.3.3.1/tests/test_argparse_type.py000066400000000000000000000071601333755710600207430ustar00rootroot00000000000000# -*- coding: utf-8 -*- # The MIT License (MIT) # # Copyright © 2014 Tim Bielawa # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. """ Test the argparse 'BitmathType' integration """ from . import TestCase import bitmath.integrations import argparse import shlex class TestArgparseType(TestCase): def setUp(self): """Needful for the tests""" # A simple one-argument parser that only accept one value. self.parser_one_arg = argparse.ArgumentParser() self.parser_one_arg.add_argument("--one-arg", type=bitmath.integrations.BitmathType) # This parser take one argument, '--two-args'. It requires two values. self.parser_two_args = argparse.ArgumentParser() self.parser_two_args.add_argument("--two-args", type=bitmath.integrations.BitmathType, nargs=2) def _parse_one_arg(self, arg_str): return self.parser_one_arg.parse_args(shlex.split(arg_str)) def _parse_two_args(self, arg_str): return self.parser_two_args.parse_args(shlex.split(arg_str)) def test_BitmathType_good_one_arg(self): """Argparse: BitmathType - Works when given a correct parameter""" args = "--one-arg 1000EB" result = self._parse_one_arg(args) self.assertEqual(bitmath.EB(1000), result.one_arg) def test_BitmathType_good_two_args(self): """Argparse: BitmathType - Works when given two correct parameters""" args = "--two-args 1337B 0.001GiB" result = self._parse_two_args(args) self.assertEqual(len(result.two_args), 2) self.assertIn(bitmath.Byte(1337), result.two_args) self.assertIn(bitmath.GiB(0.001), result.two_args) def test_BitmathType_bad_wtfareyoudoing(self): """Argparse: BitmathType - Notices when horrendously incorrect args are provided""" args = "--one-arg 2098329324kdsjflksdjf" with self.assertRaises(SystemExit): self._parse_one_arg(args) def test_BitmathType_good_spaces_in_value(self): """Argparse: BitmathType - 'Quoted values' can be separated from the units by whitespace""" args = "--two-args '100 MiB' '200 KiB'" result = self._parse_two_args(args) self.assertEqual(len(result.two_args), 2) self.assertIn(bitmath.MiB(100), result.two_args) self.assertIn(bitmath.KiB(200), result.two_args) def test_BitmathType_bad_spaces_in_value(self): """Argparse: BitmathType - Unquoted values separated from their units are detected""" args = "--one-arg 1337 B" with self.assertRaises(SystemExit): self._parse_one_arg(args) bitmath-1.3.3.1/tests/test_basic_math.py000066400000000000000000000162651333755710600201760ustar00rootroot00000000000000# -*- coding: utf-8 -*- # The MIT License (MIT) # # Copyright © 2014 Tim Bielawa # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. """ Test for basic math operations """ from . import TestCase import bitmath class TestBasicMath(TestCase): def setUp(self): self.kib_in_bytes = 1024 self.kib_in_bits = 8192 def test_type_raw_int_equality(self): """A bitmath type is equal to the value it's instanted with""" kib = bitmath.KiB(1) self.assertEqual(kib, 1) def test_same_bitmath_types_equality(self): """Two same bitmath types are equal""" self.assertEqual(bitmath.KiB(1), bitmath.KiB(1)) def test_different_bitmath_types_equality(self): """Two different bitmath types are equal""" self.assertEqual(bitmath.KiB(1), bitmath.Byte(self.kib_in_bytes)) def test_add_same_type_equal_same_type(self): """Adding the same bitmath types is equal to result as the same type""" kib1 = bitmath.KiB(1) kib2 = bitmath.KiB(1) added_two_kib = kib1 + kib2 two_kib = bitmath.KiB(2) self.assertEqual(added_two_kib, two_kib) def test_add_different_types_equal_bitmath_type(self): """Adding two different bitmath types is equal to another type of the same size""" # One Kibibyte + 1024 Bytes = 2048 bytes = Byte(2048) kib1 = bitmath.KiB(1) byte1 = bitmath.Byte(1024) added_different_types = kib1 + byte1 two_kib_in_bytes = bitmath.Byte(2048) self.assertEqual(added_different_types, two_kib_in_bytes) def test_adding_with_different_base_units(self): """Adding a bit based type with a byte based type""" kib_sized_bit_from_bytes = bitmath.Bit(self.kib_in_bits) kib = bitmath.KiB(1) added = kib_sized_bit_from_bytes + kib two_kib = bitmath.KiB(2) self.assertEqual(added, two_kib) def test_subtracting_with_different_base_units(self): """Subtracting a bit based type with a byte based type""" kib_sized_bit_from_bytes = bitmath.Bit(self.kib_in_bits) kib = bitmath.KiB(1) subtracted = kib_sized_bit_from_bytes - kib zero_kib = bitmath.KiB(0) self.assertEqual(subtracted, zero_kib) def test_absolute_positive_value(self): """abs(PositiveObject) is positive""" self.assertEqual(bitmath.KiB(1), abs(bitmath.KiB(1))) def test_absolute_negative_value(self): """abs(NegativeObject) is positive""" self.assertEqual(bitmath.KiB(1), abs(bitmath.KiB(-1))) def test_inversion_to_negative(self): """Negating a positive makes a negative""" self.assertEqual(bitmath.KiB(-1), -bitmath.KiB(1)) def test_inversion_to_positive(self): """Plus'ing a negative makes a positive""" self.assertEqual(bitmath.KiB(1), +bitmath.KiB(-1)) ################################################################## # add def bitmath_add_bitmath_is_bitmath(self): """bitmath + bitmath = bitmath""" bm1 = bitmath.KiB(1) bm2 = bitmath.KiB(2) result = bm1 + bm2 self.assertEqual(result, bitmath.KiB(3)) self.assertIs(type(result), bitmath.Byte) def test_bitmath_add_number_is_number(self): """bitmath + number = number""" bm1 = bitmath.KiB(1) num1 = 2 result = bm1 + num1 self.assertEqual(result, 3.0) self.assertIs(type(result), float) def test_number_add_bitmath_is_number(self): """number + bitmath = number""" num1 = 2 bm1 = bitmath.KiB(1) result = num1 + bm1 self.assertEqual(result, 3.0) self.assertIs(type(result), float) ################################################################## # sub def test_bitmath_sub_bitmath_is_bitmath(self): """bitmath - bitmath = bitmath""" bm1 = bitmath.KiB(1) bm2 = bitmath.KiB(2) result = bm1 - bm2 self.assertEqual(result, bitmath.KiB(-1)) self.assertIs(type(result), bitmath.KiB) def test_bitmath_sub_number_is_number(self): """bitmath - number = number""" bm1 = bitmath.KiB(1) num1 = 2 result = bm1 - num1 self.assertEqual(result, -1.0) self.assertIs(type(result), float) def test_number_sub_bitmath_is_number(self): """number - bitmath = number""" num1 = 2 bm1 = bitmath.KiB(1) result = num1 - bm1 self.assertEqual(result, 1.0) self.assertIs(type(result), float) ################################################################## # mul def test_bitmath_mul_bitmath_is_bitmath(self): """bitmath * bitmath = bitmath""" bm1 = bitmath.KiB(1) bm2 = bitmath.KiB(2) result = bm1 * bm2 self.assertEqual(result, bitmath.KiB(2048.0)) self.assertIs(type(result), bitmath.KiB) def test_bitmath_mul_number_is_bitmath(self): """bitmath * number = bitmath""" bm1 = bitmath.KiB(1) num1 = 2 result = bm1 * num1 self.assertEqual(result, bitmath.KiB(2)) self.assertIs(type(result), bitmath.KiB) def test_number_mul_bitmath_is_number(self): """number * bitmath = bitmath""" num1 = 2 bm1 = bitmath.KiB(1) result = num1 * bm1 self.assertEqual(result, bitmath.KiB(2.0)) self.assertIs(type(result), bitmath.KiB) ################################################################## # div def test_bitmath_div_bitmath_is_number(self): """bitmath / bitmath = number""" bm1 = bitmath.KiB(1) bm2 = bitmath.KiB(2) result = bm1 / bm2 self.assertEqual(result, 0.5) self.assertIs(type(result), float) def test_bitmath_div_number_is_bitmath(self): """bitmath / number = bitmath""" bm1 = bitmath.KiB(1) num1 = 2 result = bm1 / num1 self.assertEqual(result, bitmath.KiB(0.5)) self.assertIs(type(result), bitmath.KiB) def test_number_div_bitmath_is_number(self): """number / bitmath = number""" num1 = 2 bm1 = bitmath.KiB(1) result = num1 / bm1 self.assertEqual(result, 2.0) self.assertIs(type(result), float) bitmath-1.3.3.1/tests/test_best_prefix_BASE.py000066400000000000000000000077361333755710600212130ustar00rootroot00000000000000# -*- coding: utf-8 -*- # The MIT License (MIT) # # Copyright © 2014 Tim Bielawa # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. """ Test for base (Bit/Byte) prefix guessing """ from . import TestCase import bitmath class TestBestPrefixBASE(TestCase): def test_byte_round_down(self): """best_prefix_base: 4 Bits (as a Byte()) round down into a Bit()""" # Half a byte is 4 bits half_byte = bitmath.Byte(bits=4) # Byte(0.5) should round down into Bit(4) self.assertIs(type(half_byte.best_prefix()), bitmath.Bit) def test_bit_round_up(self): """best_prefix_base: 2 Bytes (as a Bit()) round up into a Byte()""" # Two bytes is 16 bits two_bytes = bitmath.Bit(bytes=2) # Bit(16) should round up into Byte(2) self.assertIs(type(two_bytes.best_prefix()), bitmath.Byte) def test_byte_no_rounding(self): """best_prefix_base: 1 Byte (as a Byte()) best prefix is still a Byte()""" # One whole byte one_byte = bitmath.Byte(1) # Byte(1.0) should stay the same, Byte(1.0) self.assertIs(type(one_byte.best_prefix()), bitmath.Byte) def test_best_prefix_with_bitmath_input(self): """best_prefix_base: can handle bitmath type inputs""" bm1 = bitmath.Byte(1024) expected = bitmath.KiB(1) self.assertEqual(bitmath.best_prefix(bm1), expected) # Negative Tests - reference: github issue #55 # # For instances where x in set { b | 0 <= abs(b) < 8 } where b is # number of bits in an instance: # # * bitmath.best_prefix(Byte(bits=-4)) -> Bit(-4) # * bitmath.best_prefix(Byte(bits=4)) -> Bit(4) def test_best_prefix_negative_less_than_a_byte(self): """best_prefix_base: negative values less than a byte stay as bits""" # assert that a Byte of -4 bits yields Bit(-4) bm1 = bitmath.Byte(bits=-4) expected = bitmath.Bit(-4) res = bitmath.best_prefix(bm1) # Verify that best prefix math works for negative numbers self.assertEqual(res, expected) # Verify that best prefix guessed the correct type self.assertIs(type(res), bitmath.Bit) # For instances where x in set { b | b >= 8 } where b is number of # bits in an instance: # # * bitmath.best_prefix(-10**8) -> MiB(-95.367...) # * bitmath.best_prefix(10**8) -> MiB(95.367...) def test_best_prefix_negative_huge_numbers(self): """best_prefix_base: large negative values retain their prefix unit""" positive_result = bitmath.best_prefix(10**8) negative_result = bitmath.best_prefix(-10**8) # Verify that the best prefix math works for negative and # positive numbers self.assertEqual(negative_result, -1 * positive_result) # Verify that they produce the same type self.assertIs(type(negative_result), type(positive_result)) # Verify that type is what we expect it to be self.assertIs(type(negative_result), bitmath.MiB) bitmath-1.3.3.1/tests/test_best_prefix_NIST.py000066400000000000000000000140121333755710600212370ustar00rootroot00000000000000# -*- coding: utf-8 -*- # The MIT License (MIT) # # Copyright © 2014 Tim Bielawa # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. """ Test for NIST prefix guessing """ from . import TestCase import bitmath class TestBestPrefixNIST(TestCase): ################################################################## # These tests verify guessing for cases where the best # representation is only one order of magnitude different. def test_simple_round_up(self): """NIST: 1 GiB (as a MiB()) rounds up into a GiB()""" # Represent a Gibibyte as a large MiB GiB_in_MiB = bitmath.MiB(1024) # This should turn into a GiB self.assertIs(type(GiB_in_MiB.best_prefix()), bitmath.GiB) def test_simple_round_down(self): """NIST: 1 MiB (as a GiB()) rounds down into a MiB()""" # Represent one MiB as a small GiB MiB_in_GiB = bitmath.GiB(bytes=1048576) # This should turn into a MiB self.assertIs(type(MiB_in_GiB.best_prefix()), bitmath.MiB) ################################################################## # These tests verify guessing for cases where the best # representation is more than one order of magnitude different. def test_multi_oom_round_up(self): """NIST: A very large Kibibyte rounds up into a Pibibyte""" large_KiB = bitmath.KiB.from_other(bitmath.PiB(1)) self.assertIs(type(large_KiB.best_prefix()), bitmath.PiB) def test_multi_oom_round_down(self): """NIST: A very small Pibibyte rounds down into a KibiByte""" small_PiB = bitmath.PiB.from_other(bitmath.KiB(1)) self.assertIs(type(small_PiB.best_prefix()), bitmath.KiB) ################################################################## # These tests mirror the multi_oom ones, except for extreme cases # where even the largest unit available results in values with # more than 4 digits left of the radix point. def test_extreme_oom_round_up(self): """NIST: 2048 EiB (as a KiB()) rounds up into an EiB()""" huge_KiB = bitmath.KiB.from_other(bitmath.EiB(1)) self.assertIs(type(huge_KiB.best_prefix()), bitmath.EiB) def test_extreme_oom_round_down(self): """NIST: 1 Bit (as a EiB()) rounds down into a Bit()""" tiny_EiB = bitmath.EiB.from_other(bitmath.Bit(1)) self.assertIs(type(tiny_EiB.best_prefix()), bitmath.Bit) ################################################################## # These tests verify that when we use the preferred prefix 'NIST' # we get a NIST type unit back. # # One test for each case. First, start with an SI unit, second, # start with a NIST unit def test_best_prefix_prefer_NIST_from_SI(self): """NIST: Best prefix honors a NIST preference when starting with an SI unit Start with an SI (kb) unit and prefer a NIST unit as the result (MiB) """ # Start with kB, an SI unit should_be_MiB = bitmath.kB(1600).best_prefix(system=bitmath.NIST) self.assertIs(type(should_be_MiB), bitmath.MiB) def test_best_prefix_prefer_NIST_from_NIST(self): """NIST: Best prefix honors a NIST preference when starting with an NIST unit Start with a NIST (GiB) unit and prefer a NIST unit as the result (MiB)""" # This should be MiB(512.0) should_be_MiB = bitmath.GiB(0.5).best_prefix(system=bitmath.NIST) self.assertIs(type(should_be_MiB), bitmath.MiB) ################################################################## def test_best_prefix_NIST_default(self): """NIST: Best prefix uses the current system if no preference set Start with a NIST unit and assert no preference. The default behavior returns a prefix from the current system family (GiB)""" # The MiB is == 1 GiB, conversion happens, and the result is a # unit from the same family (GiB) should_be_GiB = bitmath.MiB(1024).best_prefix() self.assertIs(type(should_be_GiB), bitmath.GiB) def test_best_prefix_identical_result(self): """NIST: instance.best_prefix returns the same type if nothing changes Start with a NIST unit that is already prefectly sized, and apply best_prefix() to it.""" # This is our perfectly sized unit. No change was required should_be_EiB = bitmath.EiB(1).best_prefix() self.assertIs(type(should_be_EiB), bitmath.EiB) # Let's be thorough and do that one more time self.assertIs(type(should_be_EiB.best_prefix()), bitmath.EiB) ################################################################## # Tests for the utility function bitmath.best_prefix() where # SYSTEM=NIST def test_bitmath_best_prefix_NIST(self): """bitmath.best_prefix return a Kibibyte for 1024""" result = bitmath.best_prefix(1024) self.assertIs(type(result), bitmath.KiB) def test_bitmath_best_prefix_NIST_exbi(self): """bitmath.best_prefix return an exbibyte for a huge number of bytes""" result = bitmath.best_prefix(1152921504606846977) self.assertIs(type(result), bitmath.EiB) bitmath-1.3.3.1/tests/test_best_prefix_SI.py000066400000000000000000000137251333755710600210070ustar00rootroot00000000000000# -*- coding: utf-8 -*- # The MIT License (MIT) # # Copyright © 2014 Tim Bielawa # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. """ Test for SI prefix guessing """ from . import TestCase import bitmath class TestBestPrefixSI(TestCase): ################################################################## # These tests verify guessing for cases where the best # representation is only one order of magnitude different. def test_simple_round_up(self): """SI: 1 GB (as a MB()) rounds up into a GB()""" # Represent a Gigabyte as a large MB GB_in_MB = bitmath.MB(1024) # This should turn into a GB self.assertIs(type(GB_in_MB.best_prefix()), bitmath.GB) def test_simple_round_down(self): """SI: 1 MB (as a GB()) rounds down into a MB()""" # Represent one MB as a small GB MB_in_GB = bitmath.GB(bytes=1048576) # This should turn into a MB self.assertIs(type(MB_in_GB.best_prefix()), bitmath.MB) ################################################################## # These tests verify guessing for cases where the best # representation is more than one order of magnitude different. def test_multi_oom_round_up(self): """SI: A very large Kilobyte rounds up into a Petabyte""" large_kB = bitmath.kB.from_other(bitmath.PB(1)) self.assertIs(type(large_kB.best_prefix()), bitmath.PB) def test_multi_oom_round_down(self): """SI: A very small Petabyte rounds down into a Kilobyte""" small_PB = bitmath.PB.from_other(bitmath.kB(1)) self.assertIs(type(small_PB.best_prefix()), bitmath.kB) ################################################################## # These tests mirror the multi_oom ones, except for extreme cases # where even the largest unit available results in values with # more than 4 digits left of the radix point. def test_extreme_oom_round_up(self): """SI: 2048 EB (as a kB()) rounds up into an EB()""" huge_kB = bitmath.kB.from_other(bitmath.EB(1)) self.assertIs(type(huge_kB.best_prefix()), bitmath.EB) def test_extreme_oom_round_down(self): """SI: 1 Bit (as a EB()) rounds down into a Bit()""" tiny_EB = bitmath.EB.from_other(bitmath.Bit(1)) self.assertIs(type(tiny_EB.best_prefix()), bitmath.Bit) ################################################################## # These tests verify that when we use the preferred prefix 'SI' # we get a SI type unit back which required a new prefix # # One test for each case. First, start with an SI unit, second, # start with a NIST unit def test_best_prefix_prefer_SI_from_SI(self): """SI: Best prefix honors a SI preference when starting with an SI unit Start with an SI (kb) unit and prefer a SI unit as the result (MB) """ # Start with kB, a SI unit should_be_MB = bitmath.kB(1600).best_prefix(system=bitmath.SI) self.assertIs(type(should_be_MB), bitmath.MB) def test_best_prefix_prefer_SI_from_NIST(self): """SI: Best prefix honors a SI preference when starting with a NIST unit Start with a NIST (GiB) unit and prefer a SI unit as the result (MB)""" # Start with GiB, an NIST unit should_be_MB = bitmath.GiB(0.5).best_prefix(system=bitmath.SI) self.assertIs(type(should_be_MB), bitmath.MB) ################################################################## def test_best_prefix_SI_default(self): """SI: Best prefix uses the current system if no preference set Start with a SI unit and assert no preference. The default behavior returns a prefix from the current system family (GB)""" # The MB is == 1 GB, conversion happens, and the result is a # unit from the same family (GB) should_be_GB = bitmath.MB(1000).best_prefix() self.assertIs(type(should_be_GB), bitmath.GB) def test_best_prefix_identical_result(self): """SI: best_prefix returns the same type when nothing changes Start with a SI unit that is already prefectly sized, and apply best_prefix() to it. again""" # This is our perfectly sized unit. No change was required should_be_EB = bitmath.EB(1).best_prefix() self.assertIs(type(should_be_EB), bitmath.EB) # Let's be thorough and do that one more time self.assertIs(type(should_be_EB.best_prefix()), bitmath.EB) ################################################################## # Tests for the utility function bitmath.best_prefix() where # SYSTEM=SI def test_bitmath_best_prefix_SI(self): """bitmath.best_prefix return a Kilobyte for 1024""" result = bitmath.best_prefix(1024, system=bitmath.SI) self.assertIs(type(result), bitmath.kB) def test_bitmath_best_prefix_SI_yotta(self): """bitmath.best_prefix return a yottabyte for a huge number of bytes""" result = bitmath.best_prefix(1000000000000000000000001, system=bitmath.SI) self.assertIs(type(result), bitmath.YB) bitmath-1.3.3.1/tests/test_bitwise_operations.py000066400000000000000000000052151333755710600220060ustar00rootroot00000000000000# -*- coding: utf-8 -*- # The MIT License (MIT) # # Copyright © 2014 Tim Bielawa # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. """ Test for bitwise operations: <<, >>, &, ^, | """ from . import TestCase import bitmath class TestBitwiseOperations(TestCase): def setUp(self): self.leet = bitmath.Bit(1337) def test_left_shift(self): """Bits left shifted (<<) are increased""" shifted = self.leet << 3 self.assertEqual(shifted, bitmath.Bit(10696)) def test_right_shift(self): """Bits right shifted (>>) are decreased""" shifted = self.leet >> 3 self.assertEqual(shifted, bitmath.Bit(167)) def test_and(self): """Bits and'd (&) are correct""" and_fifteen_hundred = self.leet & 1500 self.assertEqual(and_fifteen_hundred, bitmath.Bit(1304)) and_orig = self.leet & 1337 self.assertEqual(and_orig, bitmath.Bit(1337)) and_thousand = self.leet & 1000 self.assertEqual(and_thousand, bitmath.Bit(296)) and_five_hundred = self.leet & 500 self.assertEqual(and_five_hundred, bitmath.Bit(304)) def test_or(self): """Bits or'd (|) are correct""" or_thousand = self.leet | 1000 self.assertEqual(or_thousand, bitmath.Bit(2041)) or_five_hundred = self.leet | 500 self.assertEqual(or_five_hundred, bitmath.Bit(1533)) def test_xor(self): """Bits xor'd (^) are correct""" xor_thousand = self.leet ^ 1000 self.assertEqual(xor_thousand, bitmath.Bit(1745)) xor_five_hundred = self.leet ^ 500 self.assertEqual(xor_five_hundred, bitmath.Bit(1229)) bitmath-1.3.3.1/tests/test_cli.py000066400000000000000000000053571333755710600166530ustar00rootroot00000000000000# -*- coding: utf-8 -*- # The MIT License (MIT) # # Copyright © 2014 Tim Bielawa # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. """ Test the command line tool """ from . import TestCase import bitmath class TestCli(TestCase): def test_cli_script_main_no_options(self): """CLI script returns nothing if no input is given""" results = bitmath.cli_script_main([]) self.assertEqual(results, []) def test_cli_script_main_no_units(self): """CLI script works if no to/from units are provided""" args = ['100', '1024'] results = bitmath.cli_script_main(args) self.assertEqual(results[0], bitmath.Byte(100)) self.assertEqual(results[1], bitmath.KiB(1)) def test_cli_script_main_to_unit(self): """CLI script returns correct TO units""" args = ['-t', 'MiB', '1048576'] results = bitmath.cli_script_main(args) self.assertEqual(results[0], bitmath.MiB(1)) self.assertIs(type(results[0]), bitmath.MiB) def test_cli_script_main_from_unit(self): """CLI script returns correct if given FROM units""" args = ['-f', 'MiB', '0.5'] # Testing FROM 0.5 MiB TO best human readable unit (512 KiB) results = bitmath.cli_script_main(args) self.assertEqual(results[0], bitmath.KiB(512)) self.assertIs(type(results[0]), bitmath.KiB) def test_cli_script_main_from_and_to_unit(self): """CLI script returns correct if given FROM and TO units""" args = ['-f', 'MiB', '-t', 'Byte', '1'] # Testing FROM 1 MiB TO equivalent Bytes results = bitmath.cli_script_main(args) self.assertEqual(results[0], bitmath.Byte(1048576)) self.assertIs(type(results[0]), bitmath.Byte) bitmath-1.3.3.1/tests/test_context_manager.py000066400000000000000000000074311333755710600212550ustar00rootroot00000000000000# -*- coding: utf-8 -*- # The MIT License (MIT) # # Copyright © 2014 Tim Bielawa # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. """ Tests to verify that the formatting context manager works """ from . import TestCase import bitmath class TestContextManager(TestCase): def test_with_format(self): """bitmath.format context mgr sets and restores formatting""" to_print = [ bitmath.Byte(101), bitmath.KiB(202), bitmath.MB(303), bitmath.GiB(404), bitmath.TB(505), bitmath.PiB(606), bitmath.EB(707) ] str_reps = [ "101.00-Byte", "202.00-KiB", "303.00-MB", "404.00-GiB", "505.00-TB", "606.00-PiB", "707.00-EB" ] # Make sure formatting looks right BEFORE the context manager self.assertEqual(str(bitmath.KiB(1.337)), "1.337 KiB") with bitmath.format("{value:.2f}-{unit}"): for (inst, inst_str) in zip(to_print, str_reps): self.assertEqual(str(inst), inst_str) # Make sure formatting looks right AFTER the context manager self.assertEqual(str(bitmath.KiB(1.337)), "1.337 KiB") def test_print_byte_plural(self): """Byte(3.0) prints out units in plural form""" expected_result = "3Bytes" fmt_str = "{value:.1g}{unit}" three_Bytes = bitmath.Byte(3.0) with bitmath.format(plural=True): actual_result = three_Bytes.format(fmt_str) self.assertEqual(expected_result, actual_result) def test_print_byte_plural_fmt_in_mgr(self): """Byte(3.0) prints out units in plural form, setting the fmt str in the mgr""" expected_result = "3Bytes" with bitmath.format(fmt_str="{value:.1g}{unit}", plural=True): three_Bytes = bitmath.Byte(3.0) actual_result = str(three_Bytes) self.assertEqual(expected_result, actual_result) def test_print_GiB_plural_fmt_in_mgr(self): """TiB(1/3.0) prints out units in plural form, setting the fmt str in the mgr""" expected_result = "3Bytes" with bitmath.format(fmt_str="{value:.1g}{unit}", plural=True): three_Bytes = bitmath.Byte(3.0) actual_result = str(three_Bytes) self.assertEqual(expected_result, actual_result) def test_print_GiB_singular_fmt_in_mgr(self): """TiB(1/3.0) prints out units in singular form, setting the fmt str in the mgr""" expected_result = "341.3GiB" with bitmath.format(fmt_str="{value:.1f}{unit}"): third_tibibyte = bitmath.TiB(1 / 3.0).best_prefix() actual_result = str(third_tibibyte) self.assertEqual(expected_result, actual_result) bitmath-1.3.3.1/tests/test_file_size.py000066400000000000000000000234441333755710600200520ustar00rootroot00000000000000# -*- coding: utf-8 -*- # The MIT License (MIT) # # Copyright © 2014 Tim Bielawa # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. """ Tests to verify that string representations are accurate """ from . import TestCase import bitmath import os class TestFileSize(TestCase): # expected sizes are given in bytes def setUp(self): self.byte_file = './tests/file_sizes/bytes.test' self.kibibyte_file = './tests/file_sizes/kbytes.test' # ***************************************************************** # getsize # ***************************************************************** ################################################################## # NIST tests def test_getsize_byte_system_NIST(self): """NIST: getsize reports the correct type and size for byte sized files""" expected = bitmath.Byte(bytes=38) result = bitmath.getsize(self.byte_file, system=bitmath.NIST) self.assertEqual(result, expected) self.assertIs(type(result), bitmath.Byte) def test_getsize_kibibyte_system_NIST(self): """NIST: getsize reports the correct type and size for kibibyte sized files""" expected = bitmath.KiB(bytes=1024) result = bitmath.getsize(self.kibibyte_file, system=bitmath.NIST) self.assertEqual(result, expected) self.assertIs(type(result), bitmath.KiB) ################################################################## # SI tests def test_getsize_byte_system_SI(self): """SI: getsize reports the correct type and size for byte sized files""" expected = bitmath.Byte(bytes=38) result = bitmath.getsize(self.byte_file, system=bitmath.SI) self.assertEqual(result, expected) self.assertIs(type(result), bitmath.Byte) def test_getsize_kibibyte_system_SI(self): """SI: getsize reports the correct type and size for kibibyte sized files""" expected = bitmath.kB(bytes=1024) result = bitmath.getsize(self.kibibyte_file, system=bitmath.SI) self.assertEqual(result, expected) self.assertIs(type(result), bitmath.kB) # ***************************************************************** # listdir # ***************************************************************** def test_listdir_nosymlinks(self): """listdir: no symbolic links in tree measures right Assume a directory tree where no sub-directories are symbolic links:: $ tree ./tests/listdir_nosymlinks ./tests/listdir_nosymlinks `-- depth1 `-- depth2 |-- 1024_byte_file `-- 10_byte_file 2 directories, 2 files And the files, ``tests/listdir_nosymlinks/depth1/depth2/10_byte_file`` and ``tests/listdir_nosymlinks/depth1/depth2/1024_byte_file`` are 10 Bytes and 1024 Bytes in size, respectively. Then: >>> for f in bitmath.listdir('./tests/listdir_nosymlinks'): ... print f Would yield 2-tuple's of: ('/path/tests/listdir_nosymlinks/depth1/depth2/10_byte_file', Byte(10.0)) ('/path/tests/listdir_nosymlinks/depth1/depth2/1024_byte_file', KiB(1.0)) """ # Call with relpath=True so the paths are easier to verify contents = list(bitmath.listdir('./tests/listdir_nosymlinks/', relpath=True)) # Ensure the returned paths match the expected paths discovered_paths = [ contents[0][0], contents[1][0], ] expected_paths = [ 'tests/listdir_nosymlinks/depth1/depth2/10_byte_file', 'tests/listdir_nosymlinks/depth1/depth2/1024_byte_file' ] self.assertListEqual(discovered_paths, expected_paths) expected_sizes = [ bitmath.Byte(10.0), bitmath.Byte(1024.0) ] discovered_sizes = [ contents[0][1], contents[1][1] ] self.assertListEqual(discovered_sizes, expected_sizes) # 2018-03-18 - Commenting this out for now. This is failing during # RPM building. I have no idea why or when this began # happening. Tests work from the command line, but not during the # %check part of RPM building. # # It APPEARS that rpmbuild is dereferencing symlinks when # unpacking and copying the dist archive contents. Rather than # '10_byte_file_link' appearing as a link, it is a real file. # @unittest.expectedFailure # def test_listdir_symlinks_nofollow(self): # """listdir: symbolic links in tree not followed # Similar assumptions as in test_listdir_nosymlinks, except the # directory structure looks like this: # $ tree tests/listdir_symlinks # tests/listdir_symlinks # |-- 10_byte_file_link -> ../listdir/10_byte_file # `-- depth1 # `-- depth2 # `-- 10_byte_file # 2 directories, 2 files # """ # # Call with relpath=True so the paths are easier to verify # contents = list(bitmath.listdir('./tests/listdir_symlinks/', relpath=True)) # # Ensure the returned path matches the expected path # self.assertEqual(contents[0][0], 'tests/listdir_symlinks/depth1/depth2/10_byte_file') # # Ensure the measured size is what we expect # self.assertEqual(contents[0][1], bitmath.Byte(10.0)) def test_listdir_symlinks_follow(self): """listdir: symbolic links in tree are followed Same assumptions as in test_listdir_symlinks_nofollow. """ # Call with relpath=True so the paths are easier to verify contents = list(bitmath.listdir('./tests/listdir_symlinks/', followlinks=True, relpath=True)) # Ensure the returned path matches the expected path expected_paths = [ 'tests/listdir_symlinks/10_byte_file_link', 'tests/listdir_symlinks/depth1/depth2/10_byte_file' ] discovered_paths = [ contents[0][0], contents[1][0] ] self.assertListEqual(discovered_paths, expected_paths) # Ensure the measured size is what we expect expected_sizes = [ bitmath.Byte(10.0), bitmath.Byte(10.0) ] discovered_sizes = [ contents[0][1], contents[1][1] ] self.assertListEqual(discovered_sizes, expected_sizes) def test_listdir_symlinks_follow_relpath_false(self): """listdir: symlinks followed, absolute paths are returned Same assumptions as in test_listdir_symlinks_follow. Difference is that the 0th item of the tuple returns a fully qualified path. """ contents = list(bitmath.listdir('./tests/listdir_symlinks/', followlinks=True)) # Ensure the returned path matches the expected path and # begins with the present working directory pwd = os.path.realpath('.') expected_paths = [ os.path.join(pwd, contents[0][0]), os.path.join(pwd, contents[1][0]) ] discovered_paths = [ contents[0][0], contents[1][0] ] self.assertListEqual(discovered_paths, expected_paths) # Ensure the measured size is what we expect expected_sizes = [ bitmath.Byte(10.0), bitmath.Byte(10.0) ] discovered_sizes = [ contents[0][1], contents[1][1] ] self.assertListEqual(discovered_sizes, expected_sizes) def test_listdir_filtering_nosymlinks(self): """listdir: no symbolic links in tree measures right with a filter Same assumptions as test_listdir_nosymlinks.""" # Call with relpath=True so the paths are easier to verify contents = list(bitmath.listdir('./tests/listdir_nosymlinks/', relpath=True, # Should only find 1 file, 1024_byte_file filter='1024*')) # Ensure the returned path matches the expected path self.assertEqual(contents[0][0], 'tests/listdir_nosymlinks/depth1/depth2/1024_byte_file') # Ensure the measured size is what we expect self.assertEqual(contents[0][1], bitmath.KiB(1.0)) def test_listdir_filtering_empty_match_nosymlinks(self): """listdir: filtering with nosymlinks returns 0 matches for a filter Same assumptions as test_listdir_nosymlinks.""" # Call with relpath=True so the paths are easier to verify contents = list(bitmath.listdir('./tests/listdir_nosymlinks/', relpath=True, # Should find no matches filter='*notafile*')) # There should be one file discovered self.assertEqual(len(contents), int(0)) bitmath-1.3.3.1/tests/test_future_math.py000066400000000000000000000046021333755710600204170ustar00rootroot00000000000000# -*- coding: utf-8 -*- # The MIT License (MIT) # # Copyright © 2014 Tim Bielawa # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. """ Test for "future" math operations. Reference: http://legacy.python.org/dev/peps/pep-0238/ """ from __future__ import division from . import TestCase import bitmath class TestFutureMath(TestCase): def test_bitmath_div_bitmath_is_number(self): """truediv: bitmath / bitmath = number""" bm1 = bitmath.KiB(1) bm2 = bitmath.KiB(2) result = bm1 / bm2 self.assertEqual(result, 0.5) self.assertIs(type(result), float) def test_bitmath_div_number_is_bitmath(self): """truediv: bitmath / number = bitmath""" bm1 = bitmath.KiB(1) num1 = 2 result = bm1 / num1 self.assertEqual(result, bitmath.KiB(0.5)) self.assertIs(type(result), bitmath.KiB) def test_number_div_bitmath_is_number(self): """truediv: number / bitmath = number""" num1 = 2 bm1 = bitmath.KiB(1) result = num1 / bm1 self.assertEqual(result, 2.0) self.assertIs(type(result), float) def test_number_truediv_bitmath_is_number(self): """truediv: number // bitmath = number""" num1 = 2 bm1 = bitmath.KiB(1) result = bm1.__rdiv__(num1) self.assertEqual(result, 2.0) self.assertIs(type(result), float) bitmath-1.3.3.1/tests/test_init.py000066400000000000000000000053671333755710600170500ustar00rootroot00000000000000# -*- coding: utf-8 -*- # The MIT License (MIT) # # Copyright © 2015 Tim Bielawa # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. """ Test the __init__ method """ from . import TestCase import bitmath class TestInit(TestCase): def test___init__invalid_input_types(self): """__init__: can identify (in)valid input parameters, raise ValueError if detected""" invalid_inputs = ["one hundred", 100 + 6j, None] for invalid_input in invalid_inputs: with self.assertRaises(ValueError): bitmath.best_prefix(invalid_input) def test___init_multiple_kwargs(self): """__init__: respects argument mutual exclusivity""" # A 100 Byte object can be initialized with any *single* one # of these pairs: multi_kwargs = { "value": 100, # bitmath.Byte(100) "bytes": 100, # bitmath.Byte(100) "bits": 800 # bitmath.Bit(bytes=100) } with self.assertRaises(ValueError): bitmath.Byte(**multi_kwargs) def test___init__valid_inputs(self): """__init__: accepts valid inputs""" inputs = [ # Comments illustrate what the initialization calls look # like after the interpreter expands all the *arg/**kwarg # parameters. # # All pairs are equivalent to Byte(100) (used in the test # assertion, below) ((100,), dict()), # Byte(100) (tuple(), {"value": 100}), # Byte(value=100) (tuple(), {"bytes": 100}), # Byte(bytes=100) (tuple(), {"bits": 800}) # Byte(bits=800) ] for args, kwargs in inputs: self.assertEqual(bitmath.Byte(*args, **kwargs), bitmath.Byte(100)) bitmath-1.3.3.1/tests/test_instantiating.py000066400000000000000000000075721333755710600207610ustar00rootroot00000000000000# -*- coding: utf-8 -*- # The MIT License (MIT) # # Copyright © 2014 Tim Bielawa # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. """Test that bitmath instances can only be instantiated with 0 or 1 arguments. Make sure the base 'bitmath.Bitmath' class can not be instantiated either. """ from . import TestCase import bitmath class TestInstantiating(TestCase): ################################################################## # First, the simple passing tests def test_init_no_arguments(self): """Instantiation works with no arguments""" bm = bitmath.Byte() # An instance with 0 arguments will have a value of 0 self.assertEqual(bm, bitmath.Byte(0)) def test_init_value(self): """Instantiation works with only 'value' provided""" bm1 = bitmath.Byte(1) bm2 = bitmath.Byte(value=1) # These instances will be equivalent to each other and # congruent to int(1) self.assertEqual(bm1, bm2) self.assertEqual(bm1, int(1)) self.assertEqual(bm2, int(1)) def test_init_bytes(self): """Instantiation works with the 'bytes' kw arg""" bm = bitmath.Byte(bytes=1024) # 1024 bytes is 1 KiB, these should be equal self.assertEqual(bm, bitmath.KiB(1)) self.assertEqual(bm.bytes, 1024) def test_init_bits(self): """Instantiation works with the 'bits' kw arg""" bm = bitmath.Byte(bits=8) # 8 bits is 1 byte, these should be equal self.assertEqual(bm, bitmath.Byte(1)) ################################################################## # Now, the invalid uses # value and bytes def test_bad_init_value_bytes(self): """Instantiation fails if value and bytes are both provided""" with self.assertRaises(ValueError): bitmath.Byte(value=1, bytes=1) # value and bits def test_bad_init_value_bits(self): """Instantiation fails if value and bits are both provided""" with self.assertRaises(ValueError): bitmath.Byte(value=1, bits=1) # bytes and bits def test_bad_init_bytes_bits(self): """Instantiation fails if bytes and bits are both provided""" with self.assertRaises(ValueError): bitmath.Byte(bytes=1, bits=1) # value and bytes and bits def test_bad_init_value_bytes_bits(self): """Instantiation fails if value and bytes and bits are all provided""" with self.assertRaises(ValueError): bitmath.Byte(value=1, bytes=1, bits=1) ################################################################## # Double check we can't create rogue instances of bitmath.Bitmath def test_bitmath_Bitmath_cannot_be_instantiated(self): """Instantiation fails if we try to instantiate bitmath.Bitmath""" with self.assertRaises(NotImplementedError): bitmath.Bitmath(1337) bitmath-1.3.3.1/tests/test_parse.py000066400000000000000000000240641333755710600172120ustar00rootroot00000000000000# -*- coding: utf-8 -*- # The MIT License (MIT) # # Copyright © 2014 Tim Bielawa # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. """ Test parsing strings into bitmath objects """ from . import TestCase import bitmath class TestParse(TestCase): def test_parse_b(self): """parse_string works on bit strings""" self.assertEqual( bitmath.parse_string("123b"), bitmath.Bit(123)) def test_parse_B(self): """parse_string works on byte strings""" self.assertEqual( bitmath.parse_string("321B"), bitmath.Byte(321)) def test_parse_Gb(self): """parse_string works on gigabit strings""" self.assertEqual( bitmath.parse_string("456Gb"), bitmath.Gb(456)) def test_parse_MiB(self): """parse_string works on mebibyte strings""" self.assertEqual( bitmath.parse_string("654 MiB"), bitmath.MiB(654)) ###################################################################### # NIST 'octet' based units def test_parse_Mio(self): """parse_string works on mebioctet strings""" self.assertEqual( bitmath.parse_string("654 Mio"), bitmath.MiB(654)) def test_parse_Eio(self): """parse_string works on exbioctet strings""" self.assertEqual( bitmath.parse_string("654 Eio"), bitmath.EiB(654)) # SI 'octet' based units def test_parse_Mo(self): """parse_string works on megaoctet strings""" self.assertEqual( bitmath.parse_string("654 Mo"), bitmath.MB(654)) def test_parse_Eo(self): """parse_string works on exaoctet strings""" self.assertEqual( bitmath.parse_string("654 Eo"), bitmath.EB(654)) ###################################################################### def test_parse_bad_float(self): """parse_string can identify invalid float values""" with self.assertRaises(ValueError): bitmath.parse_string("1.23.45 kb") def test_parse_bad_unit(self): """parse_string can identify invalid prefix units""" with self.assertRaises(ValueError): bitmath.parse_string("1.23 GIB") def test_parse_bad_unit2(self): """parse_string can identify other prefix units""" with self.assertRaises(ValueError): bitmath.parse_string("1.23 QB") def test_parse_no_unit(self): """parse_string can identify strings without units at all""" with self.assertRaises(ValueError): bitmath.parse_string("12345") def test_parse_string_non_string_input(self): """parse_string can identify a non-string input""" with self.assertRaises(ValueError): bitmath.parse_string(12345) def test_parse_string_unicode(self): """parse_string can handle a unicode string""" self.assertEqual( bitmath.parse_string(u"750 GiB"), bitmath.GiB(750)) ###################################################################### def test_parse_unsafe_bad_input_type(self): """parse_string_unsafe can identify invalid input types""" with self.assertRaises(ValueError): invalid_input = {'keyvalue': 'store'} bitmath.parse_string_unsafe(invalid_input) def test_parse_unsafe_invalid_input(self): """parse_string_unsafe explodes when given invalid units""" invalid_input_str = "kitties!" with self.assertRaises(ValueError): bitmath.parse_string_unsafe(invalid_input_str) with self.assertRaises(ValueError): bitmath.parse_string_unsafe('100 CiB') with self.assertRaises(ValueError): bitmath.parse_string_unsafe('100 J') def test_parse_unsafe_good_number_input(self): """parse_string_unsafe can parse unitless number inputs""" number_input = 100 string_input = "100" expected_result = bitmath.Byte(100) self.assertEqual( bitmath.parse_string_unsafe(number_input), expected_result) self.assertEqual( bitmath.parse_string_unsafe(string_input), expected_result) def test_parse_unsafe_handles_SI_K_unit(self): """parse_string_unsafe can parse the upper/lowercase SI 'thousand' (k)""" thousand_lower = "100k" thousand_upper = "100K" expected_result = bitmath.kB(100) self.assertEqual( bitmath.parse_string_unsafe(thousand_lower), expected_result) self.assertEqual( bitmath.parse_string_unsafe(thousand_upper), expected_result) def test_parse_unsafe_NIST_units(self): """parse_string_unsafe can parse abbreviated NIST units (Gi, Ki, ...)""" nist_input = "100 Gi" expected_result = bitmath.GiB(100) self.assertEqual( bitmath.parse_string_unsafe(nist_input), expected_result) def test_parse_unsafe_SI(self): """parse_string_unsafe can parse all accepted SI inputs""" # Begin with the kilo unit because it's the most tricky (SI # defines the unit as a lower-case 'k') kilo_inputs = [ '100k', '100K', '100kb', '100KB', '100kB' ] expected_kilo_result = bitmath.kB(100) for ki in kilo_inputs: _parsed = bitmath.parse_string_unsafe(ki) self.assertEqual(_parsed, expected_kilo_result) self.assertIs(type(_parsed), type(expected_kilo_result)) # Now check for other easier to parse prefixes other_inputs = [ '100g', '100G', '100gb', '100gB', '100GB' ] expected_gig_result = bitmath.GB(100) for gi in other_inputs: _parsed = bitmath.parse_string_unsafe(gi) self.assertEqual(_parsed, expected_gig_result) self.assertIs(type(_parsed), type(expected_gig_result)) def test_parse_unsafe_NIST(self): """parse_string_unsafe can parse all accepted NIST inputs""" # Begin with the kilo unit because it's the most tricky (SI # defines the unit as a lower-case 'k') kilo_inputs = [ '100ki', '100Ki', '100kib', '100KiB', '100kiB' ] expected_kilo_result = bitmath.KiB(100) for ki in kilo_inputs: _parsed = bitmath.parse_string_unsafe(ki) self.assertEqual(_parsed, expected_kilo_result) self.assertIs(type(_parsed), type(expected_kilo_result)) # Now check for other easier to parse prefixes other_inputs = [ '100gi', '100Gi', '100gib', '100giB', '100GiB' ] expected_gig_result = bitmath.GiB(100) for gi in other_inputs: _parsed = bitmath.parse_string_unsafe(gi) self.assertEqual(_parsed, expected_gig_result) self.assertIs(type(_parsed), type(expected_gig_result)) def test_parse_string_unsafe_request_NIST(self): """parse_string_unsafe can convert to NIST on request""" unsafe_input = "100M" _parsed = bitmath.parse_string_unsafe(unsafe_input, system=bitmath.NIST) expected = bitmath.MiB(100) self.assertEqual(_parsed, expected) self.assertIs(type(_parsed), type(expected)) unsafe_input2 = "100k" _parsed2 = bitmath.parse_string_unsafe(unsafe_input2, system=bitmath.NIST) expected2 = bitmath.KiB(100) self.assertEqual(_parsed2, expected2) self.assertIs(type(_parsed2), type(expected2)) unsafe_input3 = "100" _parsed3 = bitmath.parse_string_unsafe(unsafe_input3, system=bitmath.NIST) expected3 = bitmath.Byte(100) self.assertEqual(_parsed3, expected3) self.assertIs(type(_parsed3), type(expected3)) unsafe_input4 = "100kb" _parsed4 = bitmath.parse_string_unsafe(unsafe_input4, system=bitmath.NIST) expected4 = bitmath.KiB(100) self.assertEqual(_parsed4, expected4) self.assertIs(type(_parsed4), type(expected4)) ###################################################################### def test_parse_string_unsafe_github_issue_60(self): """parse_string_unsafe can parse the examples reported in issue #60 https://github.com/tbielawa/bitmath/issues/60 """ issue_input1 = '7.5KB' _parsed1 = bitmath.parse_string_unsafe(issue_input1) expected_result1 = bitmath.kB(7.5) self.assertEqual( _parsed1, expected_result1) issue_input2 = '4.7MB' _parsed2 = bitmath.parse_string_unsafe(issue_input2) expected_result2 = bitmath.MB(4.7) self.assertEqual( _parsed2, expected_result2) issue_input3 = '4.7M' _parsed3 = bitmath.parse_string_unsafe(issue_input3) expected_result3 = bitmath.MB(4.7) self.assertEqual( _parsed3, expected_result3) bitmath-1.3.3.1/tests/test_progressbar.py000066400000000000000000000072351333755710600204320ustar00rootroot00000000000000# -*- coding: utf-8 -*- # The MIT License (MIT) # # Copyright © 2014 Tim Bielawa # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. """ Test the progressbar 'FileTransferSpeed' integration """ from . import TestCase import bitmath from bitmath.integrations import BitmathFileTransferSpeed import mock import progressbar class TestProgressbar(TestCase): def setUp(self): """Needful for the tests""" self.widget_NIST = BitmathFileTransferSpeed(system=bitmath.NIST) self.widget_SI = BitmathFileTransferSpeed(system=bitmath.SI) self.widget_formatted = BitmathFileTransferSpeed(format="{value:.6f} {unit_plural} per second") def test_FileTransferSpeed_0_seconds(self): """Widget renders 0 correctly when no seconds have elapsed""" pbar = mock.MagicMock(progressbar.ProgressBar) pbar.seconds_elapsed = 0 pbar.currval = 0 update = self.widget_NIST.update(pbar) self.assertEqual(update, '0.00 Byte/s') def test_FileTransferSpeed_1_seconds_Bytes(self): """Widget renders a non-zero rate after time has elapsed in Bytes""" pbar = mock.MagicMock(progressbar.ProgressBar) pbar.seconds_elapsed = 1 pbar.currval = 512 update = self.widget_NIST.update(pbar) self.assertEqual(update, '512.00 Byte/s') def test_FileTransferSpeed_10_seconds_MiB(self): """Widget renders a rate after time has elapsed in MiB/s""" pbar = mock.MagicMock(progressbar.ProgressBar) pbar.seconds_elapsed = 10 # Let's say we've downloaded 512 MiB in that time (we need # that value in Bytes, though) pbar.currval = bitmath.MiB(512).bytes update = self.widget_NIST.update(pbar) # 512 MiB in 10 seconds is equal to a rate of 51.20 MiB/s self.assertEqual(update, '51.20 MiB/s') def test_FileTransferSpeed_10_seconds_MB(self): """Widget renders a rate after time has elapsed in MB/s""" pbar = mock.MagicMock(progressbar.ProgressBar) pbar.seconds_elapsed = 10 # Let's say we've downloaded 512 MB in that time (we need that # value in Bytes, though) pbar.currval = bitmath.MB(512).bytes update = self.widget_SI.update(pbar) # 512 MB in 10 seconds is equal to a rate of 51.20 MB/s self.assertEqual(update, '51.20 MB/s') def test_FileTransferSpeed_custom_format(self): """Widget renders a custom format string""" pbar = mock.MagicMock(progressbar.ProgressBar) pbar.seconds_elapsed = 10 pbar.currval = 10240 update = self.widget_formatted.update(pbar) self.assertEqual(update, '1.000000 KiBs per second') bitmath-1.3.3.1/tests/test_properties.py000066400000000000000000000040401333755710600202640ustar00rootroot00000000000000# -*- coding: utf-8 -*- # The MIT License (MIT) # # Copyright © 2014 Tim Bielawa # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. """ Tests to verify that type properties are accessable and immutable """ from . import TestCase import bitmath class TestAttributeProperties(TestCase): def setUp(self): self.kib = bitmath.KiB(1) self.kib_bits = 8192 self.kib_bytes = 1024 self.kib_value = 1 def test_read_bits(self): """Read the 'bits' property of a bitmath type""" self.assertEqual(self.kib.bits, self.kib_bits) def test_read_bytes(self): """Read the 'bytes' property of a bitmath type""" self.assertEqual(self.kib.bytes, self.kib_bytes) def test_read_value(self): """Read the 'value' property of a bitmath type""" self.assertEqual(self.kib.value, self.kib_value) def test_write_property_fails(self): """bitmath type's properties are read-only""" with self.assertRaises(AttributeError): self.kib.value += 42 bitmath-1.3.3.1/tests/test_query_device_capacity.py000066400000000000000000000122321333755710600224330ustar00rootroot00000000000000# -*- coding: utf-8 -*- # The MIT License (MIT) # # Copyright © 2015 Tim Bielawa # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. """ Test reading block device capacities """ from . import TestCase import bitmath import mock import struct try: # Python 3.3+ from contextlib import ExitStack, contextmanager except ImportError: # Python 2.x from contextlib import nested else: @contextmanager def nested(*contexts): """Emulation of contextlib.nested in terms of ExitStack Has the problems for which "nested" was removed from Python; see: https://docs.python.org/2/library/contextlib.html#contextlib.nested But for mock.patch, these do not matter. """ with ExitStack() as stack: yield tuple(stack.enter_context(c) for c in contexts) device_file_no = mock.Mock(return_value=4) device = mock.MagicMock('file') device.fileno = device_file_no device.name = "/dev/sda" non_device_file = mock.MagicMock('file') non_device_file.name = "/home/" class TestQueryDeviceCapacity(TestCase): def test_query_device_capacity_linux_everything_is_wonderful(self): """query device capacity works on a happy Linux host""" with nested( mock.patch('os.stat'), mock.patch('stat.S_ISBLK'), mock.patch('platform.system'), mock.patch('fcntl.ioctl'), ) as (os_stat, stat_is_block, plat_system, ioctl): os_stat.return_value = mock.Mock(st_mode=25008) stat_is_block.return_value = True plat_system.return_value = 'Linux' ioctl.return_value = struct.pack('L', 244140625) # = 'QJ\x8d\x0e\x00\x00\x00\x00' # = 244140625 ~= 244.140625 MB (in SI) buffer_test = ' ' * struct.calcsize('L') bytes = bitmath.query_device_capacity(device) self.assertEqual(bytes, 244140625) self.assertEqual(ioctl.call_count, 1) ioctl.assert_called_once_with(4, 0x80081272, buffer_test) def test_query_device_capacity_mac_everything_is_wonderful(self): """query device capacity works on a happy Mac OS X host""" with nested( mock.patch('os.stat'), mock.patch('stat.S_ISBLK'), mock.patch('platform.system'), mock.patch('fcntl.ioctl'), ) as (os_stat, stat_is_block, plat_system, ioctl): # These are the struct.pack() equivalents of 244140625 # (type: u64) and 4096 (type: u32). Multiplied together # they equal the number of bytes in 1 TB. returns = [ struct.pack('L', 244140625), # 'QJ\x8d\x0e\x00\x00\x00\x00' struct.pack('I', 4096) # , '\x00\x10\x00\x00' ] def side_effect(*args, **kwargs): return returns.pop(0) os_stat.return_value = mock.Mock(st_mode=25008) stat_is_block.return_value = True plat_system.return_value = 'Darwin' ioctl.side_effect = side_effect bytes = bitmath.query_device_capacity(device) # The result should be 1 TB self.assertEqual(bytes, 1000000000000) self.assertEqual(ioctl.call_count, 2) def test_query_device_capacity_device_not_block(self): """query device capacity aborts if a non-block-device is provided""" with nested( mock.patch('os.stat'), mock.patch('stat.S_ISBLK'), mock.patch('fcntl.ioctl'), ) as (os_stat, stat_is_block, ioctl): os_stat.return_value = mock.Mock(st_mode=33204) # Force ISBLK to reject the input 'device' stat_is_block.return_value = False with self.assertRaises(ValueError): bitmath.query_device_capacity(non_device_file) self.assertEqual(ioctl.call_count, 0) def test_query_device_capacity_non_posix_system_fails(self): """query device capacity fails on a non-posix host""" with mock.patch('bitmath.os_name') as os_name: os_name.return_value = 'nt' with self.assertRaises(NotImplementedError): bitmath.query_device_capacity(device) bitmath-1.3.3.1/tests/test_representation.py000066400000000000000000000124071333755710600211400ustar00rootroot00000000000000# -*- coding: utf-8 -*- # The MIT License (MIT) # # Copyright © 2014 Tim Bielawa # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. """ Tests to verify that string representations are accurate """ from . import TestCase import bitmath class TestRepresentation(TestCase): def setUp(self): self.kib = bitmath.KiB(1) self.kib_repr = 'KiB(1.0)' self.kib_str = '1.0 KiB' self.kib_unit = 'KiB' self.kib_system = 'NIST' self.kib_bin = '0b10000000000000' self.kib_binary = self.kib_bin self.kib_power = 10 self.kib_base = 2 self.half_mib = bitmath.MiB(0.5) self.half_mib_repr = 'MiB(0.5)' self.half_mib_str = '0.5 MiB' self.kB = bitmath.kB(1) self.kB_unit = 'kB' self.kb_system = 'SI' self.kib_str_changed = 'KiB 1.000' def test_kB_unit(self): """kB(1).unit is kB""" self.assertEqual(self.kib.unit, self.kib_unit) def test_kB_system(self): """kB(1).system is SI""" self.assertEqual(self.kib.system, self.kib_system) def test_kib_unit(self): """KiB(1).unit is KiB""" self.assertEqual(self.kib.unit, self.kib_unit) def test_kib_system(self): """KiB(1).system is NIST""" self.assertEqual(self.kib.system, self.kib_system) def test_kib_binary(self): """KiB(1).binary is binary""" self.assertEqual(self.kib.binary, self.kib_binary) def test_kib_bin(self): """KiB(1).bin (binary alias) is binary""" self.assertEqual(self.kib.bin, self.kib_bin) def test_kib_base(self): """KiB(1).base is 2""" self.assertEqual(self.kib.base, self.kib_base) def test_kib_power(self): """KiB(1).power (binary alias) is 10""" self.assertEqual(self.kib.power, self.kib_power) def test_whole_kib_repr(self): """KiB(1) looks correct in a terminal""" self.assertEqual(repr(self.kib), self.kib_repr) def test_whole_kib_str(self): """KiB(1) looks correct as a string""" self.assertEqual(str(self.kib), self.kib_str) def test_half_mib_repr(self): """MiB(0.5) looks correct in a terminal""" self.assertEqual(repr(self.half_mib), self.half_mib_repr) def test_half_mib_str(self): """MiB(0.5) looks correct as a string""" self.assertEqual(str(self.half_mib), self.half_mib_str) ################################################################## # Test custom formatting def test_print_two_digits_precision(self): """MiB(1/3.0) prints out with two digits of precision""" expected_result = "0.33MiB" fmt_str = "{value:.2f}{unit}" third_MiB = bitmath.MiB(1 / 3.0) actual_result = third_MiB.format(fmt_str) self.assertEqual(expected_result, actual_result) def test_print_scientific_four_digits_precision(self): """MiB(102.4754) prints out with four digits of precision""" expected_result = "102.5MiB" fmt_str = "{value:.4g}{unit}" third_MiB = bitmath.MiB(102.4754) actual_result = third_MiB.format(fmt_str) self.assertEqual(expected_result, actual_result) def test_longer_formatting_string(self): """KiB(12345) as a MiB (12.0556640625) truncates to 5 digits""" expected_result = "12.05566 MiB" fmt_str = "{value:.5f} {unit}" instance = bitmath.KiB(12345).to_MiB() actual_result = instance.format(fmt_str) self.assertEqual(expected_result, actual_result) def test_change_format_string(self): """KiB(1.0) looks right if changing fmt str in bitmath.KiB NOTE: This does NOT make use of the bitmath.format context manager. There is a separate test suite for that: test_context_manager""" orig_fmt_str = bitmath.format_string bitmath.format_string = "{unit} {value:.3f}" kib = bitmath.KiB(1) self.assertEqual(self.kib_str_changed, str(kib)) bitmath.format_string = orig_fmt_str def test_print_byte_singular(self): """Byte(1.0) prints out units in singular form""" expected_result = "1Byte" fmt_str = "{value:.2g}{unit}" one_Byte = bitmath.Byte(1.0) actual_result = one_Byte.format(fmt_str) self.assertEqual(expected_result, actual_result) bitmath-1.3.3.1/tests/test_rich_comparison.py000066400000000000000000000077051333755710600212620ustar00rootroot00000000000000# -*- coding: utf-8 -*- # The MIT License (MIT) # # Copyright © 2014 Tim Bielawa # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. """ Test for rich comparison operations: LT, LE, EQ, NE, GT, GE """ from . import TestCase import bitmath class TestRichComparison(TestCase): def setUp(self): self.kib = bitmath.KiB(1) self.mib = bitmath.MiB(1) self.gib = bitmath.GiB(1) ################################################################## # Test bitmath comparisons def test_less_than(self): """One KiB is less than one MiB""" self.assertLess(self.kib, self.mib) def test_less_than_equal(self): """Smaller or equal is less than or equal to one MiB""" # True - 1 KiB is less than 1 MiB self.assertLessEqual(self.kib, self.mib) # True - 1024 KiB is equal to 1 MiB self.assertLessEqual(bitmath.KiB(1024), self.mib) def test_greater_than(self): """1 GiB is greater than 1 Mib""" self.assertGreater(self.gib, self.mib) def test_greater_than_equal(self): """Greater or equal is more than or equal to one MiB""" # True - 1 GiB is greater than 1 MiB self.assertGreaterEqual(self.gib, self.mib) # True - 1024 KiB is equal to 1 MiB self.assertGreaterEqual(self.mib, bitmath.GiB(1 / 1024.0)) ################################################################## # Same tests, but against numbers instead of bitmaths def test_less_than_num(self): """One KiB is less than int(2)""" self.assertLess(self.kib, 2) def test_less_than_equal_num(self): """Smaller or equal is less than or equal to int(2)""" # True - 1 KiB is less than 2 self.assertLessEqual(self.kib, 2) # True - 1024 KiB is equal to 1024 self.assertLessEqual(bitmath.KiB(1024), 1024) def test_greater_than_num(self): """1 GiB is greater than 0.5""" self.assertGreater(self.gib, 0.5) def test_greater_than_equal_num(self): """Greater or equal is more than or equal to int(1)""" # True - 1 GiB is equal to 1 self.assertGreaterEqual(self.gib, 1) # True - 1024 KiB is greater than 0.5 self.assertGreaterEqual(self.mib, 0.5) ################################################################## # Equality testing def test_equal(self): """Two equal values are actually equal""" self.assertEqual(self.mib, bitmath.KiB(1024)) def test_equal_false(self): """Unequal objects aren't equal""" self.assertNotEqual(self.kib, self.gib) ################################################################## # Equality testing against numbers def test_equal_num(self): """Two equal values are actually equal with numbers""" self.assertEqual(self.mib, 1) def test_equal_false_num(self): """Unequal objects aren't equal with numbers""" self.assertNotEqual(self.kib, 42) bitmath-1.3.3.1/tests/test_sorting.py000066400000000000000000000103411333755710600175560ustar00rootroot00000000000000# -*- coding: utf-8 -*- # The MIT License (MIT) # # Copyright © 2014 Tim Bielawa # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. """ Test proper sorting operations """ from . import TestCase import bitmath class TestSorting(TestCase): def test_sort_homogeneous_list(self): """Same types in a list can be sorted properly""" first = bitmath.kB(0) second = bitmath.kB(1337) third = bitmath.kB(2048) fourth = bitmath.kB(96783) # Put the objects into the array in 'random' order unsorted_list = [fourth, second, first, third] sorted_list = sorted(unsorted_list) self.assertIs(sorted_list[0], first) self.assertIs(sorted_list[1], second) self.assertIs(sorted_list[2], third) self.assertIs(sorted_list[3], fourth) def test_sort_heterogeneous_list(self): """Different types in a list can be sorted properly Define these with the bytes keyword so we don't lose our minds trying to figure out if the results are correct.""" first = bitmath.KiB(bytes=0) second = bitmath.GiB(bytes=1337) third = bitmath.Eb(bytes=2048) fourth = bitmath.Byte(bytes=96783) unsorted_list = [fourth, second, first, third] sorted_list = sorted(unsorted_list) self.assertIs(sorted_list[0], first) self.assertIs(sorted_list[1], second) self.assertIs(sorted_list[2], third) self.assertIs(sorted_list[3], fourth) def test_sort_key_bytes(self): """Bitmath types can be sorted by 'bytes' attribute""" first = bitmath.kB(0) second = bitmath.kB(1337) third = bitmath.kB(2048) fourth = bitmath.kB(96783) unsorted_list = [fourth, second, first, third] sorted_list = sorted(unsorted_list, key=lambda x: x.bytes) self.assertIs(sorted_list[0], first) self.assertIs(sorted_list[1], second) self.assertIs(sorted_list[2], third) self.assertIs(sorted_list[3], fourth) def test_sort_key_bits(self): """Bitmath types can be sorted by 'bits' attribute""" first = bitmath.kB(0) second = bitmath.kB(1337) third = bitmath.kB(2048) fourth = bitmath.kB(96783) unsorted_list = [fourth, second, first, third] sorted_list = sorted(unsorted_list, key=lambda x: x.bits) self.assertIs(sorted_list[0], first) self.assertIs(sorted_list[1], second) self.assertIs(sorted_list[2], third) self.assertIs(sorted_list[3], fourth) def test_sort_key_value(self): """Same types can be sorted by 'value' attribute This does not work on heterogeneous collections! The 'value' attribute varies between different bitmath types even if they are of equivalent size because it is the shortened representation of that prefix unit.""" first = bitmath.kB(0) second = bitmath.kB(1337) third = bitmath.kB(2048) fourth = bitmath.kB(96783) unsorted_list = [fourth, second, first, third] sorted_list = sorted(unsorted_list, key=lambda x: x.value) self.assertIs(sorted_list[0], first) self.assertIs(sorted_list[1], second) self.assertIs(sorted_list[2], third) self.assertIs(sorted_list[3], fourth) bitmath-1.3.3.1/tests/test_to_Type_conversion.py000066400000000000000000000246571333755710600220000ustar00rootroot00000000000000# -*- coding: utf-8 -*- # The MIT License (MIT) # # Copyright © 2014 Tim Bielawa # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. """ Test to verify the bitmath.Type.to_Type() conversions work """ from . import TestCase import bitmath class TestToTypeConversion(TestCase): def setUp(self): self.bit = bitmath.Bit(1) self.byte = bitmath.Byte(1) # NIST units self.kib = bitmath.KiB(1) self.mib = bitmath.MiB(1) self.gib = bitmath.GiB(1) self.tib = bitmath.TiB(1) self.pib = bitmath.PiB(1) self.eib = bitmath.EiB(1) # SI units self.kb = bitmath.kB(1) self.mb = bitmath.MB(1) self.gb = bitmath.GB(1) self.tb = bitmath.TB(1) self.pb = bitmath.PB(1) self.eb = bitmath.EB(1) self.zb = bitmath.ZB(1) self.yb = bitmath.YB(1) def test_to_same_unit(self): """bitmath type converted to the same unit is properly converted""" to_kib = self.kib.to_KiB() self.assertIs(type(to_kib), bitmath.KiB) self.assertIs(type(self.kib.KiB), bitmath.KiB) def test_from_other(self): """MiB object from_other object""" mib_from_kib = bitmath.MiB.from_other(bitmath.KiB(1)) self.assertIs(type(mib_from_kib), bitmath.MiB) ################################################################## # to b's def test_to_Bit(self): """Convert to Bit""" self.assertIs(type(self.kb.to_Bit()), bitmath.Bit) self.assertIs(type(self.kb.Bit), bitmath.Bit) def test_to_Byte(self): """Convert to Byte""" self.assertIs(type(self.kb.to_Byte()), bitmath.Byte) self.assertIs(type(self.kb.Byte), bitmath.Byte) ################################################################## # to k's def test_to_KiB(self): """Convert to KiB""" to_kib = self.mib.to_KiB() self.assertIs(type(to_kib), bitmath.KiB) self.assertIs(type(self.mib.KiB), bitmath.KiB) def test_to_Kib(self): """Convert to Kib""" to_kib = self.mib.to_Kib() self.assertIs(type(to_kib), bitmath.Kib) self.assertIs(type(self.mib.Kib), bitmath.Kib) def test_to_kb(self): """Convert to kb""" to_kb = self.mib.to_kb() self.assertIs(type(to_kb), bitmath.kb) self.assertIs(type(self.mib.kb), bitmath.kb) ################################################################## # to m's def test_to_MiB(self): """Convert a bitmath GiB into a MiB""" to_mib = self.gib.to_MiB() self.assertIs(type(to_mib), bitmath.MiB) self.assertIs(type(self.gib.MiB), bitmath.MiB) def test_to_Mib(self): """Convert a bitmath GiB into a Mib""" to_mib = self.gib.to_Mib() self.assertIs(type(to_mib), bitmath.Mib) self.assertIs(type(self.gib.Mib), bitmath.Mib) def test_to_MB(self): """Convert a bitmath GiB into a MB""" to_mb = self.gib.to_MB() self.assertIs(type(to_mb), bitmath.MB) self.assertIs(type(self.gib.MB), bitmath.MB) def test_to_Mb(self): """Convert a bitmath GiB into a Mb""" to_mb = self.gib.to_Mb() self.assertIs(type(to_mb), bitmath.Mb) self.assertIs(type(self.gib.Mb), bitmath.Mb) ################################################################## # to g's def test_to_GiB(self): """Convert a bitmath TiB into a GiB""" to_gib = self.tib.to_GiB() self.assertIs(type(to_gib), bitmath.GiB) self.assertIs(type(self.tib.GiB), bitmath.GiB) def test_to_Gib(self): """Convert a bitmath GiB into a Gib""" to_gib = self.gib.to_Gib() self.assertIs(type(to_gib), bitmath.Gib) self.assertIs(type(self.tib.Gib), bitmath.Gib) def test_to_GB(self): """Convert a bitmath GiB into a GB""" to_gb = self.gib.to_GB() self.assertIs(type(to_gb), bitmath.GB) self.assertIs(type(self.tib.GB), bitmath.GB) def test_to_Gb(self): """Convert a bitmath GiB into a Gb""" to_gb = self.gib.to_Gb() self.assertIs(type(to_gb), bitmath.Gb) self.assertIs(type(self.tib.Gb), bitmath.Gb) ################################################################## # to t's def test_to_TiB(self): """Convert a bitmath PiB into a TiB""" to_tib = self.pib.to_TiB() self.assertIs(type(to_tib), bitmath.TiB) self.assertIs(type(self.pib.TiB), bitmath.TiB) def test_to_Tib(self): """Convert a bitmath GiB into a Tib""" to_tib = self.gib.to_Tib() self.assertIs(type(to_tib), bitmath.Tib) self.assertIs(type(self.pib.Tib), bitmath.Tib) def test_to_TB(self): """Convert a bitmath GiB into a TB""" to_tb = self.gib.to_TB() self.assertIs(type(to_tb), bitmath.TB) self.assertIs(type(self.pib.TB), bitmath.TB) def test_to_Tb(self): """Convert a bitmath GiB into a Tb""" to_tb = self.gib.to_Tb() self.assertIs(type(to_tb), bitmath.Tb) self.assertIs(type(self.pib.Tb), bitmath.Tb) ################################################################## # to p's def test_to_PiB(self): """Convert a bitmath TiB into a PiB""" to_pib = self.tib.to_PiB() self.assertIs(type(to_pib), bitmath.PiB) self.assertIs(type(self.tib.PiB), bitmath.PiB) def test_to_Pib(self): """Convert a bitmath GiB into a PiB""" to_pib = self.gib.to_Pib() self.assertIs(type(to_pib), bitmath.Pib) self.assertIs(type(self.gib.Pib), bitmath.Pib) def test_to_PB(self): """Convert a bitmath GiB into a PB""" to_pb = self.gib.to_PB() self.assertIs(type(to_pb), bitmath.PB) self.assertIs(type(self.gib.PB), bitmath.PB) def test_to_Pb(self): """Convert a bitmath GiB into a Pb""" to_pb = self.gib.to_Pb() self.assertIs(type(to_pb), bitmath.Pb) self.assertIs(type(self.gib.Pb), bitmath.Pb) ################################################################## # to e's def test_to_EiB(self): """Convert a bitmath PiB into a EiB""" to_eib = self.pib.to_EiB() self.assertIs(type(to_eib), bitmath.EiB) self.assertIs(type(self.pib.EiB), bitmath.EiB) def test_to_Eib(self): """Convert a bitmath GiB into a Eib""" to_eib = self.gib.to_Eib() self.assertIs(type(to_eib), bitmath.Eib) self.assertIs(type(self.pib.Eib), bitmath.Eib) def test_to_EB(self): """Convert a bitmath GiB into a EB""" to_eb = self.gib.to_EB() self.assertIs(type(to_eb), bitmath.EB) self.assertIs(type(self.pib.EB), bitmath.EB) def test_to_Eb(self): """Convert a bitmath GiB into a Eb""" to_eb = self.gib.to_Eb() self.assertIs(type(to_eb), bitmath.Eb) self.assertIs(type(self.pib.Eb), bitmath.Eb) ################################################################## # to z's def test_to_ZB(self): """Convert a bitmath GiB into a ZB""" to_zb = self.gib.to_ZB() self.assertIs(type(to_zb), bitmath.ZB) self.assertIs(type(self.pib.ZB), bitmath.ZB) def test_to_Zb(self): """Convert a bitmath GiB into a Zb""" to_zb = self.gib.to_Zb() self.assertIs(type(to_zb), bitmath.Zb) self.assertIs(type(self.pib.Zb), bitmath.Zb) ################################################################## # to y's def test_to_YB(self): """Convert a bitmath GiB into a YB""" to_yb = self.gib.to_YB() self.assertIs(type(to_yb), bitmath.YB) self.assertIs(type(self.pib.YB), bitmath.YB) def test_to_Yb(self): """Convert a bitmath GiB into a Yb""" to_yb = self.gib.to_Yb() self.assertIs(type(to_yb), bitmath.Yb) self.assertIs(type(self.pib.Yb), bitmath.Yb) ################################################################## # to other stuff def test_to_mib_from_bit(self): """Convert a bitmath Bit into a MiB""" to_mib = self.bit.to_MiB() self.assertIs(type(to_mib), bitmath.MiB) def test_converted_up_bitmath_value_equivalency(self): """Converted up type has an equivalent value to the original""" # Take a KiB, make a MiB from it. Test their equality to_mib = self.kib.to_MiB() self.assertEqual(self.kib, to_mib) # Two tests, to be "thorough" to_gib = self.mib.to_GiB() self.assertEqual(self.mib, to_gib) def test_converted_down_bitmath_value_equivalency(self): """Converted down type has an equivalent value to the original""" # Take a MiB, make a KiB from it. Test their equality to_kib = self.mib.to_KiB() self.assertEqual(to_kib, self.mib) def test_convert_nist_to_si(self): """Convert an NIST unit into an SI unit""" kb_from_kib = self.kib.to_kB() self.assertIs(type(kb_from_kib), bitmath.kB) def test_convert_si_to_nist(self): """Convert an SI unit into an NIST unit""" kib_from_kb = self.kb.to_KiB() self.assertIs(type(kib_from_kb), bitmath.KiB) ################################################################## # Naughty bad bad test cases def test_from_other_bad_input(self): """from_other raises if "other" isn't a bitmath instance""" with self.assertRaises(ValueError): bitmath.Byte.from_other(str("not a bitmath instance!")) bitmath-1.3.3.1/tests/test_to_built_in_conversion.py000066400000000000000000000034621333755710600226530ustar00rootroot00000000000000# -*- coding: utf-8 -*- # The MIT License (MIT) # # Copyright © 2014 Tim Bielawa # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. """ Test to verify the int/float/long conversions work correctly """ from . import TestCase import bitmath import sys # Python 3.x compat if sys.version > '3': long = int class TestToBuiltInConversion(TestCase): def test_to_int(self): """int(bitmath) returns an int""" gib = bitmath.GiB(1337.8) self.assertIs(type(int(gib)), int) def test_to_float(self): """float(bitmath) returns a float""" gib = bitmath.GiB(1337.8) self.assertIs(type(float(gib)), float) def test_to_long(self): """long(bitmath) returns a long""" gib = bitmath.GiB(1337.8) self.assertIs(type(long(gib)), long) bitmath-1.3.3.1/tests/test_unique_testcase_names.sh000077500000000000000000000004671333755710600224520ustar00rootroot00000000000000#!/bin/bash grep class tests/*.py | awk '{ arr[$NF]++ } END { for (word in arr) { if (arr[word] != "1") { printf "DUPLICATES: %s %d\n", word, arr[word] } } }' | grep -q "DUPLICATES" if (( ! $? )); then echo "Error: Duplicate TestCase class names found" exit 1 fi bitmath-1.3.3.1/tests/test_utils.py000066400000000000000000000042741333755710600172410ustar00rootroot00000000000000# -*- coding: utf-8 -*- # The MIT License (MIT) # # Copyright © 2014 Tim Bielawa # # Permission is hereby granted, free of charge, to any person # obtaining a copy of this software and associated documentation files # (the "Software"), to deal in the Software without restriction, # including without limitation the rights to use, copy, modify, merge, # publish, distribute, sublicense, and/or sell copies of the Software, # and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be # included in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS # BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN # ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE # SOFTWARE. """ Test utility functions """ from . import TestCase import bitmath class TestUtils(TestCase): def test_capitalize_first_normal_word(self): """capitalize_first upcases just the first letter in a word""" word1 = "foo" expected1 = "Foo" self.assertEqual( bitmath.capitalize_first(word1), expected1) word2 = "foO" expected2 = "FoO" self.assertEqual( bitmath.capitalize_first(word2), expected2) def test_capitalize_first_starts_with_number(self): """capitalize_first doesn't change anything if the input begins with a number""" word = "1foo" expected = "1foo" self.assertEqual( bitmath.capitalize_first(word), expected) def test_capitalize_first_already_capped(self): """capitalize_first doesn't change anything if the input is already correct""" word = "Foo" expected = "Foo" self.assertEqual( bitmath.capitalize_first(word), expected)