├── .gitignore ├── README.rst ├── main.py ├── setup.py └── stackoverflow └── __init__.py /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### Python template 3 | # Byte-compiled / optimized / DLL files 4 | __pycache__/ 5 | *.py[cod] 6 | *$py.class 7 | 8 | # C extensions 9 | *.so 10 | 11 | # Distribution / packaging 12 | .Python 13 | env/ 14 | build/ 15 | develop-eggs/ 16 | dist/ 17 | downloads/ 18 | eggs/ 19 | .eggs/ 20 | lib/ 21 | lib64/ 22 | parts/ 23 | sdist/ 24 | var/ 25 | *.egg-info/ 26 | .installed.cfg 27 | *.egg 28 | 29 | # PyInstaller 30 | # Usually these files are written by a python script from a template 31 | # before PyInstaller builds the exe, so as to inject date/other infos into it. 32 | *.manifest 33 | *.spec 34 | 35 | # Installer logs 36 | pip-log.txt 37 | pip-delete-this-directory.txt 38 | 39 | # Unit test / coverage reports 40 | htmlcov/ 41 | .tox/ 42 | .coverage 43 | .coverage.* 44 | .cache 45 | nosetests.xml 46 | coverage.xml 47 | *,cover 48 | .hypothesis/ 49 | 50 | # Translations 51 | *.mo 52 | *.pot 53 | 54 | # Django stuff: 55 | *.log 56 | local_settings.py 57 | 58 | # Flask stuff: 59 | instance/ 60 | .webassets-cache 61 | 62 | # Scrapy stuff: 63 | .scrapy 64 | 65 | # Sphinx documentation 66 | docs/_build/ 67 | 68 | # PyBuilder 69 | target/ 70 | 71 | # IPython Notebook 72 | .ipynb_checkpoints 73 | 74 | # pyenv 75 | .python-version 76 | 77 | # celery beat schedule file 78 | celerybeat-schedule 79 | 80 | # dotenv 81 | .env 82 | 83 | # virtualenv 84 | venv/ 85 | ENV/ 86 | 87 | # Spyder project settings 88 | .spyderproject 89 | 90 | # Rope project settings 91 | .ropeproject 92 | 93 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | StackOverflow Importer 2 | ====================== 3 | 4 | Do you ever feel like all you’re doing is copy/pasting from Stack 5 | Overflow? 6 | 7 | Let’s take it one step further. 8 | 9 | | ``from stackoverflow import quick_sort`` will go through the search 10 | results 11 | | of ``[python] quick sort`` looking for the largest code block that 12 | doesn’t 13 | | syntax error in the highest voted answer from the highest voted 14 | question 15 | | and return it as a module. If that answer doesn’t have any valid 16 | python 17 | | code, it checks the next highest voted answer for code blocks. 18 | 19 | .. code:: python 20 | 21 | >>> from stackoverflow import quick_sort, split_into_chunks 22 | 23 | >>> print(quick_sort.sort([1, 3, 2, 5, 4])) 24 | [1, 2, 3, 4, 5] 25 | 26 | >>> print(list(split_into_chunks.chunk("very good chunk func"))) 27 | ['very ', 'good ', 'chunk', ' func'] 28 | 29 | >>> print("I wonder who made split_into_chunks", split_into_chunks.__author__) 30 | I wonder who made split_into_chunks https://stackoverflow.com/a/35107113 31 | 32 | >>> print("but what's the license? Can I really use this?", quick_sort.__license__) 33 | but what's the license? Can I really use this? CC BY-SA 3.0 34 | >>> assert("nice, attribution!") 35 | 36 | This module is licensed under whatever license you want it to be as 37 | long as the license is compatible with the fact that I blatantly 38 | copied multiple lines of code from the Python standard library. 39 | -------------------------------------------------------------------------------- /main.py: -------------------------------------------------------------------------------- 1 | from stackoverflow import quick_sort, split_into_chunks 2 | print(quick_sort.sort([1, 3, 2, 5, 4])) 3 | print(list(split_into_chunks.chunk("very good chunk func"))) 4 | print("gotta take a break") 5 | from time import time 6 | t1 = time() 7 | from stackoverflow import time_delay 8 | print("that's enough, let's continue", time()-t1) 9 | print("I wonder who made split_into_chunks", split_into_chunks.__author__) 10 | print("but what's the license? Can I really use this?", quick_sort.__license__) 11 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | """A setuptools based setup module. 2 | 3 | See: 4 | https://packaging.python.org/en/latest/distributing.html 5 | https://github.com/pypa/sampleproject 6 | """ 7 | 8 | from setuptools import setup 9 | from codecs import open 10 | from os import path 11 | 12 | here = path.abspath(path.dirname(__file__)) 13 | 14 | with open(path.join(here, 'README.rst'), encoding='utf-8') as f: 15 | long_description = f.read() 16 | 17 | setup( 18 | name='stackoverflow', 19 | version='0.1.0', 20 | description='A sample Python project', 21 | long_description=long_description, 22 | url='https://github.com/drathier/stack-overflow-import', 23 | author='https://github.com/drathier', 24 | author_email='fille.haglund@hotmail.com', 25 | license='WTFPL', 26 | classifiers=[ 27 | 'Development Status :: 3 - Alpha', 28 | 'Intended Audience :: Developers', 29 | 'Topic :: Software Development :: Build Tools', 30 | 'Programming Language :: Python :: 3', 31 | 'Programming Language :: Python :: 3.3', 32 | 'Programming Language :: Python :: 3.4', 33 | 'Programming Language :: Python :: 3.5', 34 | ], 35 | keywords='stackoverflow development boilerplate', 36 | packages=["stackoverflow"], 37 | install_requires=['requests'], 38 | ) 39 | -------------------------------------------------------------------------------- /stackoverflow/__init__.py: -------------------------------------------------------------------------------- 1 | import ast 2 | import html 3 | import re 4 | import sys 5 | from importlib._bootstrap import spec_from_loader 6 | 7 | import requests 8 | 9 | 10 | class StackOverflowImporter: 11 | """ 12 | `from stackoverflow import quick_sort` will go through the search results 13 | of `[python] quick sort` looking for the largest code block that doesn't 14 | syntax error in the highest voted answer from the highest voted question 15 | and return it as a module, or raise ImportError if there's no code at all. 16 | """ 17 | API_URL = "https://api.stackexchange.com" 18 | 19 | @classmethod 20 | def find_spec(cls, fullname, path=None, target=None): 21 | spec = spec_from_loader(fullname, cls, origin='hell') 22 | spec.__license__ = "CC BY-SA 3.0" 23 | spec._url = cls._fetch_url(spec.name) 24 | spec._code, spec.__author__ = cls._fetch_code(spec._url) 25 | return spec 26 | 27 | @classmethod 28 | def create_module(cls, spec): 29 | """Create a built-in module""" 30 | return spec 31 | 32 | @classmethod 33 | def exec_module(cls, module=None): 34 | """Exec a built-in module""" 35 | try: 36 | exec(module._code, module.__dict__) 37 | except: 38 | print(module._url) 39 | print(module._code) 40 | raise 41 | 42 | @classmethod 43 | def get_code(cls, fullname): 44 | return compile(cls._fetch_code(cls._fetch_url(fullname)), 'StackOverflow.com/' + fullname, 'exec') 45 | 46 | @classmethod 47 | def get_source(cls, fullname): 48 | return cls.get_code(fullname) 49 | 50 | @classmethod 51 | def is_package(cls, fullname): 52 | return False 53 | 54 | ############################ 55 | 56 | @classmethod 57 | def _fetch_url(cls, query): 58 | query = query.lower().replace("stackoverflow.", "").replace("_", " ") 59 | ans = requests.get(cls.API_URL + "/search", { 60 | "order": "desc", 61 | "sort": "votes", 62 | "tagged": "python", 63 | "site": "stackoverflow", 64 | "intitle": query, 65 | }).json() 66 | if not ans["items"]: 67 | raise ImportError("Couldn't find any question matching `" + query + "`") 68 | return ans["items"][0]["link"] 69 | 70 | @classmethod 71 | def _fetch_code(cls, url): 72 | q = requests.get(url) 73 | return cls._find_code_in_html(q.text) 74 | 75 | @staticmethod 76 | def _find_code_in_html(s): 77 | answers = re.findall(r'
]*>((?:\s|[^<]|]*>[^<]+)*)
", answer)
89 | codez = map(lambda x: x.group(1), codez)
90 | for code in sorted(codez, key=lambda x: -len(x)): # more code is obviously better
91 | # don't forget attribution
92 | author = s
93 | author = author[author.find(code):]
94 | author = author[:author.find(">share<")]
95 | author = author[author.rfind(']+>([^<]*)<[^>]*>", "\1", code)
102 | try:
103 | ast.parse(code)
104 | return code, author_link # it compiled! uhm, parsed!
105 | except:
106 | pass
107 | else: # https://stackoverflow.com/questions/9979970/why-does-python-use-else-after-for-and-while-loops
108 | raise ImportError("This question ain't got no good code.")
109 |
110 |
111 | sys.meta_path.append(StackOverflowImporter())
112 |
--------------------------------------------------------------------------------