{"id":22772207,"url":"https://github.com/stuart-wilcox/servepy","last_synced_at":"2025-09-12T19:37:38.028Z","repository":{"id":57465845,"uuid":"114596522","full_name":"Stuart-Wilcox/servepy","owner":"Stuart-Wilcox","description":"Servepy is a simple Python HTTP server framework","archived":false,"fork":false,"pushed_at":"2020-10-29T20:39:49.000Z","size":70,"stargazers_count":1,"open_issues_count":5,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-09-04T21:03:06.024Z","etag":null,"topics":["http-server","lightweight","python3","server-framework"],"latest_commit_sha":null,"homepage":"https://pypi.python.org/pypi/servepy/1.0.3","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Stuart-Wilcox.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-12-18T04:41:03.000Z","updated_at":"2020-10-29T20:39:51.000Z","dependencies_parsed_at":"2022-09-19T07:52:06.437Z","dependency_job_id":null,"html_url":"https://github.com/Stuart-Wilcox/servepy","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Stuart-Wilcox/servepy","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Stuart-Wilcox%2Fservepy","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Stuart-Wilcox%2Fservepy/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Stuart-Wilcox%2Fservepy/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Stuart-Wilcox%2Fservepy/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Stuart-Wilcox","download_url":"https://codeload.github.com/Stuart-Wilcox/servepy/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Stuart-Wilcox%2Fservepy/sbom","scorecard":{"id":135002,"data":{"date":"2025-08-04","repo":{"name":"github.com/Stuart-Wilcox/servepy","commit":"df315cfb265489785bb34183c7d69ca9aa21d74d"},"scorecard":{"version":"v5.2.1-28-gc1d103a9","commit":"c1d103a9bb9f635ec7260bf9aa0699466fa4be0e"},"score":2.9,"checks":[{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#sast"}},{"name":"Binary-Artifacts","score":9,"reason":"binaries present in source code","details":["Warn: binary detected: __pycache__/serve.cpython-35.pyc:1"],"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#binary-artifacts"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#dangerous-workflow"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 0/27 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#code-review"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#token-permissions"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#packaging"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#fuzzing"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#signed-releases"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE.txt:0","Info: FSF or OSI recognized license: MIT License: LICENSE.txt:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#license"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/c1d103a9bb9f635ec7260bf9aa0699466fa4be0e/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-16T06:15:51.182Z","repository_id":57465845,"created_at":"2025-08-16T06:15:51.182Z","updated_at":"2025-08-16T06:15:51.182Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274864469,"owners_count":25364232,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-09-12T02:00:09.324Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["http-server","lightweight","python3","server-framework"],"created_at":"2024-12-11T17:06:58.029Z","updated_at":"2025-09-12T19:37:37.962Z","avatar_url":"https://github.com/Stuart-Wilcox.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# servepy 1.0.3\n\nservepy is a web server framework inspired by Express.js\n\nFor more info, installation and usage visit [servepy's official site](https://stuart-wilcox.github.io/servepy-site/main)\n\n## Contents\n[Installation](#installation)\n- [Pip](#pip)\n\n[Usage](#usage)\n- [Simple Usage](#simple-usage)\n- [Sample](#sample)\n\n[Documentation](#documentation)\n- [App](#app)\n- [Router](#router)\n- [Request](#request)\n- [Response](#response)\n\n## Installation\nThe fastest and easiest way to install servepy is using [pip](https://pip.pypa.io/en/stable/). If you don't have pip, you can get it [here](https://pip.pypa.io/en/stable/installing/), but if you installed python properly you should alread have it. Before continuing, make sure to update pip by running ```pip install --upgrade pip``` for Windows and ```sudo pip3 install --upgrade pip``` for Linux.\n\n### Pip\nThis is the recommended way to get servepy.\n\nWindows ```pip install servepy```\nLinux ```sudo -H pip3 install servepy```\n\nIt's that easy, and now you can simply use ```import servepy```.\n\n*NOTE: If you get warnings about failing to build the wheel file, just ignore them it should still work.*\n\n\n## Usage\n### Simple Usage\nThis is a demo for a very simple usage to demonstrate the core concepts.\n\nIn a new terminal, navigate to your project directory and make two files, server.py and handlers.py, just like below.\n```[python]\n# server.py\nimport servepy\nimport handlers\n\napp = servepy.App()\nrouter = servepy.Router()\n\n# this specifies that a GET request to url path '/' will execute the function handlers.getRoot\nrouter.get('/', handlers.getRoot)\n\n# mount the router on the app\napp.use(router)\n\n# start the server\napp.listen(port=8080, hostname='localhost')\n```\n```[python]\n# handlers.py\n\ndef getRoot(req, res):\n  req.set('Content-Type', 'text/plain') # set the Content-Type header to text/plain\n  req.status(200) # set the HTTP status to 200 OK\n  req.send('Hello world!') # send the string as the response body\n```\nExecute your server in a terminal (command prompt)\n\nIn your web browser (or if you prefer, a REST API client like Postman or Insomnia), navigate to http://localhost:8080/ to see the message 'Hello World'. To stop the server, issue a keyboard interrupt with CTRL+C.\n\n### Sample\n\nTo see a working example, look at what is in the [sample directory](./sample). In here, there are two files: ```home.html``` and ```server.py```. The latter is the server code and the former is a very simple html file to render in a browser.\n\nTo run the sample, in a temrinal (command prompt) navigate to the root of the servepy directory and simply execute sample. Windows: ```sample.bat``` \u003cbr/\u003e\nLinux: ```sample.sh```\n\n*NOTE: Linux users will most likely need to give execution permission to ```sample.sh```. To do so, in the project directory use the command ```$ sudo chmod +x sample.sh```.*\n\n## Documentation\n\n### App\n#### Properties\n###### locals\nThe app.locals object has properties that are local variables within the application. Once set, the value of app.locals properties persits throughout the life of the application.\n###### mountpath\nThe app.mountpath property contains one or more path patterns on which the sub-app was mounted.\n\n#### Methods\n###### all(path, callback)\nThis method is like using app.METHOD(...) but for all HTTP verbs\n###### delete(path, callback)\nRoutes HTTP DELETE requests to the specified path with the specified callback function(s)\n###### get(path, callback)\nRoutes HTTP GET requests to the specified path with the specified callback function(s)\n###### listen([path], [callback], [port], [hostname])\nStarts a socket and listens for connections on the given path.\n###### post(path, callback)\nRoutes HTTP POST requests to the specified path with the specified callback(s)\n###### route(path)\nReturns an instance of a single route which can be used like a router\n###### use(callback [, path])\nMount the specified middleware function(s) or router(s) at the specified path. If no path is provided, '/' is used.\n\n### Router\n#### Methods\n###### all(path, callback)\nThis method is just like the ```router.METHOD()``` methods, except that it matches all HTTP methods (verbs).\n\nThis method is extremely useful for mapping “global” logic for specific path prefixes or arbitrary matches.\n###### METHOD(path, callback)\nThe ```router.METHOD()``` methods provide the routing functionality, where ```METHOD``` is one of the HTTP methods, such as ```GET```,  ```PUT```, ```POST```, and ```DELETE```, in lowercase. Thus, the actual methods are ```router.get()```, ```router.post()```, ```router.put()```, and ```router.delete()```.\n###### param(name, callback)\nAdds callback triggers to route parameters, where name is the ```name``` of the parameter and ```callback``` is the callback function.\n###### route(path)\nReturns an instance of a single route which you can then use to handle HTTP verbs with optional middleware. Use ```router.route()``` to avoid duplicate route naming and thus typing errors.\n###### use(function [,path])\nUses the specified middleware ```function```, with optional mount path ```path```, that defaults to '/'.\n\nThis method is similar to ```app.use()```. A simple example and use case is described below. See ```app.use()``` for more information.\n\n### Request\n#### Properties\n###### app\nThis property holds a reference to the instance of the Express application that is using the middleware.\n###### body\nContains an object representing the data submitted in the request body (if there is one). By default, it is ```None``` and will be automatically populated if a body is not present on a request.\n**NOTE: Support only exists for parsing bodies of the following Content-Type: text/plain, application/json, application/x-www-form-urlencoded**\n###### cookies\n**NOTE: Not implemented yet**\u003cbr/\u003e\nContains the cookies sent by the request. If there are no cookies, it defaults to ```None```.\n###### fresh\nIndicates whether the request is 'fresh'. It is the opposite of ```req.stale```. It is true if the ```cache-control``` request header doesn't have a ```no-cache``` directive and any of the following are true:\n  - The ```if-modified-since``` request header is specified and ```last-modified``` request header is equal to or earlier than the modified response header\n  - The ```if-none-match``` request header is *\n  - The ```if-none-match``` request header, after being parsed into its directives, does not match the ```stage``` response header.\n\n###### hostname\nContains the hostname derived from the ```Host``` HTTP header. When the trust proxy setting does not evaluate to false, this property will instead have the value of the ```X-Forwarded-Host``` header field. This header can be set by the client or by the proxy.\n###### method\nContains a string corresponding to the HTTP method if the request: ```GET, POST, PUT, DELETE, ...etc.```\n\u003cbr/\u003e**NOTE: Support only exists for GET, POST, PUT \u0026 DELETE. Other methods such as HEAD, OPTIONS, etc. are not yet supported**\n###### originalUrl\nThis property is much like ```req.url```; however, it retains the original request URL, allowing you to rewrite it freely for internal routing purposes. For example, the \"mounting\" feature of ```app.use()``` will rewrite ```req.url``` to strip the mount point\n###### params\nThis property is a ```dict``` containing the properties mapped to the names path parameters. For example, if you have the route ```/user/:name```, then \"name\" property is available as ```req.params['name']```. The dictionary defaults to ```{}``` if no path parameters are used.\n###### path\nContains the path part of the request URL.\n###### protocol\nContains the request protocol string, ex: ```HTTP/1.1```\n###### query\nThis property is a ```dict``` containing a property for each query string parameter in the route. If there is no query string, it is ```{}```; an empty dictionary\n###### route\nContains the currently-matched route, a string\n###### stale\nIndicates whether the request is \"stale\", and it is the opposite of fresh. (See req.fresh)\n###### xhr\nA Boolean property that is ```True``` if the request's ```X-Requested-With``` header is \"XMLHttpRequest\", indicating that the request was issued by a client library such as JQuery\n#### Methods\n###### accepts(types)\nChecks if the specified content types are acceptable, based on the request’s ```Accept``` HTTP header field. The method returns the best match, or if none of the specified content types is acceptable, returns ```False``` (in which case, the application should respond with 406 \"Not Acceptable\")\n###### get(field)\nReturns the specified HTTP request header field (case-insensitive match). The Referrer and Referer fields are interchangeable\n###### is_type(type)\nReturns the matching content type if the incoming request’s ```Content-Type``` HTTP header field matches the MIME type specified by the type parameter. Returns ```False``` otherwise\n\n\n### Response\n#### Properties\n###### app\nThis property holds a reference to the instance of the Express application that is using the middleware.\nIt is identical to the ```req.app``` property in the request object.\n###### header_sent\nBoolean property that indicates if the app sent HTTP headers for the response.\n\n#### Methods\n###### append(field [, value])\nAppends the specified value to the HTTP response header field. If the header is not already set, it creates the header with the specified value. The value parameter can be a string or an array. If the header is already set, the value given as a parameter will be ignored and the value in place will remain.\n\nNote: calling ```res.set()``` after ```res.append()``` will reset the previously-set header value.\n###### attachment([filename])\nSets the HTTP response ```Content-Disposition``` header field to “attachment”. If a filename is given, then it sets the ```Content-Type``` based on the extension name, and sets the ```Content-Disposition``` “filename=” parameter.\n###### cookie(name, value [, options])\n**NOTE: Not implemented yet**\u003cbr/\u003e\nSets cookie name to value. The value parameter may be a string or object.\n\nThe options parameter is an object that can have the following properties.\n###### clearCookie(name [, options])\n**NOTE: Not implemented yet**\u003cbr/\u003e\nClears the cookie specified by name. For details about the options object, see ```res.cookie()```.\n\n###### get(field)\nReturns the HTTP response header specified by field. The match is case-insensitive.\n###### json([body])\nSends a JSON response. This method sends a response (with the correct content-type) that is the parameter converted to a JSON string.\n\nThe parameter can be any JSON type, meaning the built in types (```boolean, int, float, complex, list, tuple, dict, str, bytes, ... etc.```), and you can also use it to convert other values to JSON, such as ```None```(although this is technically not valid JSON).\n\n###### send([body])\nSends the HTTP response.\n\nThe body parameter can be a ```str```, ```object```, ```tuple```, ```dict``` or a ```list```.\n\n###### set(field [, value])\nSets the response’s HTTP header ```field``` to ```value```. To set multiple fields at once, pass an object as the parameter.\n###### status(code)\nSets the HTTP status for the response.\n###### type(type)\nSets the ```Content-Type``` HTTP header to the MIME type as determined by the specified type.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstuart-wilcox%2Fservepy","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstuart-wilcox%2Fservepy","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstuart-wilcox%2Fservepy/lists"}