Skip to content

Commit 0559729

Browse files
committed
initial commit
0 parents  commit 0559729

File tree

8 files changed

+320
-0
lines changed

8 files changed

+320
-0
lines changed

.gitignore

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
# Byte-compiled / optimized / DLL files
2+
__pycache__/
3+
*.py[cod]
4+
*$py.class
5+
6+
# C extensions
7+
*.so
8+
9+
# Distribution / packaging
10+
.Python
11+
build/
12+
develop-eggs/
13+
dist/
14+
downloads/
15+
eggs/
16+
.eggs/
17+
lib/
18+
lib64/
19+
parts/
20+
sdist/
21+
var/
22+
wheels/
23+
*.egg-info/
24+
.installed.cfg
25+
*.egg
26+
MANIFEST
27+
28+
# PyInstaller
29+
# Usually these files are written by a python script from a template
30+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
31+
*.manifest
32+
*.spec
33+
34+
# Installer logs
35+
pip-log.txt
36+
pip-delete-this-directory.txt
37+
38+
# Unit test / coverage reports
39+
htmlcov/
40+
.tox/
41+
.coverage
42+
.coverage.*
43+
.cache
44+
nosetests.xml
45+
coverage.xml
46+
*.cover
47+
.hypothesis/
48+
49+
# Translations
50+
*.mo
51+
*.pot
52+
53+
# Django stuff:
54+
*.log
55+
.static_storage/
56+
.media/
57+
local_settings.py
58+
59+
# Flask stuff:
60+
instance/
61+
.webassets-cache
62+
63+
# Scrapy stuff:
64+
.scrapy
65+
66+
# Sphinx documentation
67+
docs/_build/
68+
69+
# PyBuilder
70+
target/
71+
72+
# Jupyter Notebook
73+
.ipynb_checkpoints
74+
75+
# pyenv
76+
.python-version
77+
78+
# celery beat schedule file
79+
celerybeat-schedule
80+
81+
# SageMath parsed files
82+
*.sage.py
83+
84+
# Environments
85+
.env
86+
.venv
87+
env/
88+
venv/
89+
ENV/
90+
env.bak/
91+
venv.bak/
92+
93+
# Spyder project settings
94+
.spyderproject
95+
.spyproject
96+
97+
# Rope project settings
98+
.ropeproject
99+
100+
# mkdocs documentation
101+
/site
102+
103+
# mypy
104+
.mypy_cache/

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Pandas Flavor
2+
**Flavor Pandas objects with your own methods and accessors.**
3+
4+
Easily register new methods and accessors with Pandas objects.
5+
6+
![](docs/_images/example.png)
7+
8+
Pandas added `register_series_accessor` and `register_dataframe_accessor` decorators
9+
in 0.23. These extensions allow you to easily add new accessors to Pandas objects that
10+
are persistent. This means, you can easily write your own flavor of the DataFrame.
11+
12+
To see an example, checkout [pdvega](). This library adds a new Vega plotting accessor
13+
under the `vgplot` attribute and mirror the `plot` (matplotlib-based) accessor.
14+
15+
**Pandas Flavor** takes this extension module a step further and adds similar syntax
16+
for registering new methods!
17+
18+
To see an example, check out [PhyloPandas](https://github.com/Zsailer/phylopandas).
19+
This library adds extra `to_` methods for writing DataFrames to various biological
20+
sequencing file formats.
21+
22+
## How it works

docs/_images/example.png

43.2 KB
Loading

pandas_flavor/__init__.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from .register import (register_series_method,
2+
register_series_accessor,
3+
register_dataframe_method,
4+
register_dataframe_accessor)

pandas_flavor/__version__.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__version__ = '0.1.0'

pandas_flavor/pandas_internals.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
try:
2+
# Import register decorators from pandas >= 0.23
3+
from pandas.api.extensions import (register_dataframe_accessor,
4+
register_series_accessor)
5+
except ImportError:
6+
try:
7+
from pandas.core.accessor import AccessorProperty
8+
except ImportError: # Pandas before 0.22.0
9+
from pandas.core.base import AccessorProperty
10+
11+
# Define register decorators for pandas < 0.23
12+
class register_dataframe_accessor(object):
13+
"""Register custom accessor on DataFrame."""
14+
def __init__(self, name):
15+
self.name = name
16+
17+
def __call__(self, accessor):
18+
setattr(DataFrame, self.name, AccessorProperty(accessor, accessor))
19+
20+
class register_series_accessor(object):
21+
"""Register custom accessor on Series."""
22+
def __init__(self, name):
23+
self.name = name
24+
25+
def __call__(self, accessor):
26+
setattr(Series, self.name, AccessorProperty(accessor, accessor))

pandas_flavor/register.py

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
from .pandas_internals import (register_series_accessor,
2+
register_dataframe_accessor)
3+
4+
5+
def register_dataframe_method(method):
6+
"""Register a function as a method attached to the Pandas DataFrame.
7+
8+
Example
9+
-------
10+
11+
.. code-block:: python
12+
13+
@register_dataframe_method
14+
def print_column(df, col):
15+
'''Print the dataframe column given'''
16+
print(df[col])
17+
"""
18+
def inner(*args, **kwargs):
19+
20+
class AccessorMethod(object):
21+
__doc__ = method.__doc__
22+
23+
def __init__(self, pandas_obj):
24+
self._obj = pandas_obj
25+
26+
def __call__(self, *args, **kwargs):
27+
return method(self._obj, *args, **kwargs)
28+
29+
register_dataframe_accessor(method.__name__)(AccessorMethod)
30+
31+
return inner()
32+
33+
34+
def register_series_method(method):
35+
"""Register a function as a method attached to the Pandas Series.
36+
"""
37+
def inner(*args, **kwargs):
38+
39+
class AccessorMethod(object):
40+
__doc__ = method.__doc__
41+
42+
def __init__(self, pandas_obj):
43+
self._obj = pandas_obj
44+
45+
def __call__(self, *args, **kwargs):
46+
return method(self._obj, *args, **kwargs)
47+
48+
register_series_accessor(method.__name__)(AccessorMethod)
49+
50+
return inner()

setup.py

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
#!/usr/bin/env python
2+
# -*- coding: utf-8 -*-
3+
4+
# Note: To use the 'upload' functionality of this file, you must:
5+
# $ pip install twine
6+
7+
import io
8+
import os
9+
import sys
10+
from shutil import rmtree
11+
12+
from setuptools import find_packages, setup, Command
13+
14+
# Package meta-data.
15+
NAME = 'pandas_flavor'
16+
DESCRIPTION = 'The easy way to write your own Pandas flavor.'
17+
URL = 'https://github.com/Zsailer/pandas_flavor'
18+
19+
AUTHOR = 'Zach Sailer'
20+
21+
# What packages are required for this module to be executed?
22+
REQUIRED = ["pandas"]
23+
24+
# The rest you shouldn't have to touch too much :)
25+
# ------------------------------------------------
26+
# Except, perhaps the License and Trove Classifiers!
27+
# If you do change the License, remember to change the Trove Classifier for that!
28+
29+
here = os.path.abspath(os.path.dirname(__file__))
30+
31+
# Import the README and use it as the long-description.
32+
# Note: this will only work if 'README.rst' is present in your MANIFEST.in file!
33+
with io.open(os.path.join(here, 'README.md'), encoding='utf-8') as f:
34+
long_description = '\n' + f.read()
35+
36+
# Load the package's __version__.py module as a dictionary.
37+
about = {}
38+
with open(os.path.join(here, NAME, '__version__.py')) as f:
39+
exec(f.read(), about)
40+
41+
42+
class UploadCommand(Command):
43+
"""Support setup.py upload."""
44+
45+
description = 'Build and publish the package.'
46+
user_options = []
47+
48+
@staticmethod
49+
def status(s):
50+
"""Prints things in bold."""
51+
print('\033[1m{0}\033[0m'.format(s))
52+
53+
def initialize_options(self):
54+
pass
55+
56+
def finalize_options(self):
57+
pass
58+
59+
def run(self):
60+
try:
61+
self.status('Removing previous builds…')
62+
rmtree(os.path.join(here, 'dist'))
63+
except OSError:
64+
pass
65+
66+
self.status('Building Source and Wheel (universal) distribution…')
67+
os.system('{0} setup.py sdist bdist_wheel --universal'.format(sys.executable))
68+
69+
self.status('Uploading the package to PyPi via Twine…')
70+
os.system('twine upload dist/*')
71+
72+
sys.exit()
73+
74+
75+
# Where the magic happens:
76+
setup(
77+
name=NAME,
78+
version=about['__version__'],
79+
description=DESCRIPTION,
80+
long_description=long_description,
81+
author=AUTHOR,
82+
author_email=EMAIL,
83+
url=URL,
84+
packages=find_packages(exclude=('tests',)),
85+
# If your package is a single module, use this instead of 'packages':
86+
# py_modules=['mypackage'],
87+
88+
# entry_points={
89+
# 'console_scripts': ['mycli=mymodule:cli'],
90+
# },
91+
install_requires=REQUIRED,
92+
include_package_data=True,
93+
license='MIT',
94+
classifiers=[
95+
# Trove classifiers
96+
# Full list: https://pypi.python.org/pypi?%3Aaction=list_classifiers
97+
'License :: OSI Approved :: MIT License',
98+
'Programming Language :: Python',
99+
'Programming Language :: Python :: 2.6',
100+
'Programming Language :: Python :: 2.7',
101+
'Programming Language :: Python :: 3',
102+
'Programming Language :: Python :: 3.3',
103+
'Programming Language :: Python :: 3.4',
104+
'Programming Language :: Python :: 3.5',
105+
'Programming Language :: Python :: 3.6',
106+
'Programming Language :: Python :: Implementation :: CPython',
107+
'Programming Language :: Python :: Implementation :: PyPy'
108+
],
109+
# $ setup.py publish support.
110+
cmdclass={
111+
'upload': UploadCommand,
112+
},
113+
)

0 commit comments

Comments
 (0)